DATACASS-470 - Move Cassandra type resolution into MappingCassandraConverter.
All DataType-resolution functionality is now encapsulated in ColumnTypeResolver and all DataType-related methods (getDataType(), getTupleType(), getUserType()) were migrated into ColumnTypeResolver. DataType resolution requires always a converter context to apply registered converters so this concern cannot be handled entirely on the mapping level. Related to type resolution also schema object derivation (create table/index/user type) functionality was moved from CassandraMappingContext into SchemaFactory as schema object derivation requires the converter registrations.
This commit is contained in:
@@ -68,12 +68,17 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf
|
|||||||
@Bean
|
@Bean
|
||||||
public CassandraConverter cassandraConverter() {
|
public CassandraConverter cassandraConverter() {
|
||||||
|
|
||||||
MappingCassandraConverter mappingCassandraConverter =
|
UserTypeResolver userTypeResolver = new SimpleUserTypeResolver(getRequiredSession(),
|
||||||
new MappingCassandraConverter(requireBeanOfType(CassandraMappingContext.class));
|
CqlIdentifier.fromCql(getKeyspaceName()));
|
||||||
|
|
||||||
mappingCassandraConverter.setCustomConversions(requireBeanOfType(CassandraCustomConversions.class));
|
MappingCassandraConverter converter = new MappingCassandraConverter(
|
||||||
|
requireBeanOfType(CassandraMappingContext.class));
|
||||||
|
|
||||||
return mappingCassandraConverter;
|
converter.setCodecRegistry(getRequiredSession().getContext().getCodecRegistry());
|
||||||
|
converter.setUserTypeResolver(userTypeResolver);
|
||||||
|
converter.setCustomConversions(requireBeanOfType(CassandraCustomConversions.class));
|
||||||
|
|
||||||
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,11 +91,11 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf
|
|||||||
@Bean
|
@Bean
|
||||||
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
|
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
|
||||||
|
|
||||||
UserTypeResolver userTypeResolver =
|
UserTypeResolver userTypeResolver = new SimpleUserTypeResolver(getRequiredSession(),
|
||||||
new SimpleUserTypeResolver(getRequiredSession(), CqlIdentifier.fromCql(getKeyspaceName()));
|
CqlIdentifier.fromCql(getKeyspaceName()));
|
||||||
|
|
||||||
CassandraMappingContext mappingContext =
|
CassandraMappingContext mappingContext = new CassandraMappingContext(userTypeResolver,
|
||||||
new CassandraMappingContext(userTypeResolver, SimpleTupleTypeFactory.DEFAULT);
|
SimpleTupleTypeFactory.DEFAULT);
|
||||||
|
|
||||||
CustomConversions customConversions = requireBeanOfType(CustomConversions.class);
|
CustomConversions customConversions = requireBeanOfType(CustomConversions.class);
|
||||||
|
|
||||||
@@ -156,8 +161,8 @@ public abstract class AbstractCassandraConfiguration extends AbstractSessionConf
|
|||||||
/**
|
/**
|
||||||
* Configures the Java {@link ClassLoader} used to resolve Cassandra application entity {@link Class types}.
|
* Configures the Java {@link ClassLoader} used to resolve Cassandra application entity {@link Class types}.
|
||||||
*
|
*
|
||||||
* @param classLoader Java {@link ClassLoader} used to resolve Cassandra application entity {@link Class types};
|
* @param classLoader Java {@link ClassLoader} used to resolve Cassandra application entity {@link Class types}; may
|
||||||
* may be {@literal null}.
|
* be {@literal null}.
|
||||||
* @see java.lang.ClassLoader
|
* @see java.lang.ClassLoader
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.data.cassandra.core.convert.SchemaFactory;
|
||||||
import org.springframework.data.cassandra.core.mapping.Table;
|
import org.springframework.data.cassandra.core.mapping.Table;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
@@ -34,6 +35,12 @@ import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
|
|||||||
*/
|
*/
|
||||||
public interface CassandraAdminOperations extends CassandraOperations {
|
public interface CassandraAdminOperations extends CassandraOperations {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link SchemaFactory}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
SchemaFactory getSchemaFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a table with the name given and fields corresponding to the given class. If the table already exists and
|
* Create a table with the name given and fields corresponding to the given class. If the table already exists and
|
||||||
* parameter {@code ifNotExists} is {@literal true}, this is a no-op and {@literal false} is returned. If the table
|
* parameter {@code ifNotExists} is {@literal true}, this is a no-op and {@literal false} is returned. If the table
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import org.springframework.data.cassandra.SessionFactory;
|
import org.springframework.data.cassandra.SessionFactory;
|
||||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||||
|
import org.springframework.data.cassandra.core.convert.SchemaFactory;
|
||||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||||
import org.springframework.data.cassandra.core.cql.SessionCallback;
|
import org.springframework.data.cassandra.core.cql.SessionCallback;
|
||||||
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||||
@@ -48,6 +49,8 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
|||||||
|
|
||||||
protected static final boolean DEFAULT_DROP_TABLE_IF_EXISTS = false;
|
protected static final boolean DEFAULT_DROP_TABLE_IF_EXISTS = false;
|
||||||
|
|
||||||
|
private final SchemaFactory schemaFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor used for a basic template configuration.
|
* Constructor used for a basic template configuration.
|
||||||
*
|
*
|
||||||
@@ -56,6 +59,8 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
|||||||
*/
|
*/
|
||||||
public CassandraAdminTemplate(CqlSession session) {
|
public CassandraAdminTemplate(CqlSession session) {
|
||||||
super(session);
|
super(session);
|
||||||
|
|
||||||
|
this.schemaFactory = new SchemaFactory(getConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,6 +71,7 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
|||||||
*/
|
*/
|
||||||
public CassandraAdminTemplate(CqlSession session, CassandraConverter converter) {
|
public CassandraAdminTemplate(CqlSession session, CassandraConverter converter) {
|
||||||
super(session, converter);
|
super(session, converter);
|
||||||
|
this.schemaFactory = new SchemaFactory(getConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,6 +82,8 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
|||||||
*/
|
*/
|
||||||
public CassandraAdminTemplate(SessionFactory sessionFactory, CassandraConverter converter) {
|
public CassandraAdminTemplate(SessionFactory sessionFactory, CassandraConverter converter) {
|
||||||
super(sessionFactory, converter);
|
super(sessionFactory, converter);
|
||||||
|
|
||||||
|
this.schemaFactory = new SchemaFactory(getConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,6 +95,13 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
|||||||
*/
|
*/
|
||||||
public CassandraAdminTemplate(CqlOperations cqlOperations, CassandraConverter converter) {
|
public CassandraAdminTemplate(CqlOperations cqlOperations, CassandraConverter converter) {
|
||||||
super(cqlOperations, converter);
|
super(cqlOperations, converter);
|
||||||
|
|
||||||
|
this.schemaFactory = new SchemaFactory(getConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SchemaFactory getSchemaFactory() {
|
||||||
|
return schemaFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -98,8 +113,8 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
|||||||
|
|
||||||
CassandraPersistentEntity<?> entity = getConverter().getMappingContext().getRequiredPersistentEntity(entityClass);
|
CassandraPersistentEntity<?> entity = getConverter().getMappingContext().getRequiredPersistentEntity(entityClass);
|
||||||
|
|
||||||
CreateTableSpecification createTableSpecification = getConverter().getMappingContext()
|
CreateTableSpecification createTableSpecification = this.schemaFactory
|
||||||
.getCreateTableSpecificationFor(tableName, entity).ifNotExists(ifNotExists);
|
.getCreateTableSpecificationFor(entity, tableName).ifNotExists(ifNotExists);
|
||||||
|
|
||||||
getCqlOperations().execute(CreateTableCqlGenerator.toCql(createTableSpecification));
|
getCqlOperations().execute(CreateTableCqlGenerator.toCql(createTableSpecification));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,22 @@ public class CassandraPersistentEntitySchemaCreator {
|
|||||||
|
|
||||||
private final CassandraMappingContext mappingContext;
|
private final CassandraMappingContext mappingContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link CassandraPersistentEntitySchemaCreator} for the given {@link CassandraMappingContext} and
|
||||||
|
* {@link CassandraAdminOperations}.
|
||||||
|
*
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
* @param cassandraAdminOperations must not be {@literal null}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public CassandraPersistentEntitySchemaCreator(CassandraAdminOperations cassandraAdminOperations) {
|
||||||
|
|
||||||
|
Assert.notNull(cassandraAdminOperations, "CassandraAdminOperations must not be null");
|
||||||
|
|
||||||
|
this.cassandraAdminOperations = cassandraAdminOperations;
|
||||||
|
this.mappingContext = cassandraAdminOperations.getConverter().getMappingContext();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link CassandraPersistentEntitySchemaCreator} for the given {@link CassandraMappingContext} and
|
* Create a new {@link CassandraPersistentEntitySchemaCreator} for the given {@link CassandraMappingContext} and
|
||||||
* {@link CassandraAdminOperations}.
|
* {@link CassandraAdminOperations}.
|
||||||
@@ -96,7 +112,8 @@ public class CassandraPersistentEntitySchemaCreator {
|
|||||||
|
|
||||||
return this.mappingContext.getTableEntities() //
|
return this.mappingContext.getTableEntities() //
|
||||||
.stream() //
|
.stream() //
|
||||||
.map(entity -> this.mappingContext.getCreateTableSpecificationFor(entity).ifNotExists(ifNotExists)) //
|
.map(entity -> cassandraAdminOperations.getSchemaFactory().getCreateTableSpecificationFor(entity)
|
||||||
|
.ifNotExists(ifNotExists)) //
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +139,7 @@ public class CassandraPersistentEntitySchemaCreator {
|
|||||||
|
|
||||||
return this.mappingContext.getTableEntities() //
|
return this.mappingContext.getTableEntities() //
|
||||||
.stream() //
|
.stream() //
|
||||||
.flatMap(entity -> this.mappingContext.getCreateIndexSpecificationsFor(entity).stream()) //
|
.flatMap(entity -> cassandraAdminOperations.getSchemaFactory().getCreateIndexSpecificationsFor(entity).stream()) //
|
||||||
.peek(it -> it.ifNotExists(ifNotExists)) //
|
.peek(it -> it.ifNotExists(ifNotExists)) //
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@@ -161,11 +178,10 @@ public class CassandraPersistentEntitySchemaCreator {
|
|||||||
visitUserTypes(entity, udts);
|
visitUserTypes(entity, udts);
|
||||||
});
|
});
|
||||||
|
|
||||||
specifications
|
specifications.addAll(udts.stream()
|
||||||
.addAll(udts
|
.map(identifier -> cassandraAdminOperations.getSchemaFactory()
|
||||||
.stream().map(identifier -> this.mappingContext
|
.getCreateUserTypeSpecificationFor(byTableName.get(identifier)).ifNotExists(ifNotExists))
|
||||||
.getCreateUserTypeSpecificationFor(byTableName.get(identifier)).ifNotExists(ifNotExists))
|
.collect(Collectors.toList()));
|
||||||
.collect(Collectors.toList()));
|
|
||||||
|
|
||||||
return specifications;
|
return specifications;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public interface CassandraColumnType extends ColumnType {
|
|||||||
* Returns the {@link DataType} associated with this column type.
|
* Returns the {@link DataType} associated with this column type.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @throws org.springframework.data.mapping.MappingException if the column cannot be mapped onto a Cassandra type.
|
||||||
*/
|
*/
|
||||||
DataType getDataType();
|
DataType getDataType();
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import org.springframework.data.util.TypeInformation;
|
|||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Central Cassandra specific converter interface from Object to Row.
|
* Central Cassandra specific converter interface from Object to Row.
|
||||||
*
|
*
|
||||||
@@ -42,6 +44,14 @@ public interface CassandraConverter
|
|||||||
*/
|
*/
|
||||||
CustomConversions getCustomConversions();
|
CustomConversions getCustomConversions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link CodecRegistry} registered in the {@link CassandraConverter}.
|
||||||
|
*
|
||||||
|
* @return the {@link CodecRegistry}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
CodecRegistry getCodecRegistry();
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.convert.EntityConverter#getMappingContext()
|
* @see org.springframework.data.convert.EntityConverter#getMappingContext()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ public interface ColumnType {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static CassandraColumnType listOf(CassandraColumnType componentType) {
|
static CassandraColumnType listOf(CassandraColumnType componentType) {
|
||||||
return new DefaultCassandraColumnType(ClassTypeInformation.LIST, DataTypes.listOf(componentType.getDataType()),
|
return new DefaultCassandraColumnType(ClassTypeInformation.LIST,
|
||||||
componentType);
|
() -> DataTypes.listOf(componentType.getDataType()), componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,7 +114,7 @@ public interface ColumnType {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static CassandraColumnType setOf(CassandraColumnType componentType) {
|
static CassandraColumnType setOf(CassandraColumnType componentType) {
|
||||||
return new DefaultCassandraColumnType(ClassTypeInformation.SET, DataTypes.setOf(componentType.getDataType()),
|
return new DefaultCassandraColumnType(ClassTypeInformation.SET, () -> DataTypes.setOf(componentType.getDataType()),
|
||||||
componentType);
|
componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ public interface ColumnType {
|
|||||||
*/
|
*/
|
||||||
static CassandraColumnType mapOf(CassandraColumnType keyType, CassandraColumnType valueType) {
|
static CassandraColumnType mapOf(CassandraColumnType keyType, CassandraColumnType valueType) {
|
||||||
return new DefaultCassandraColumnType(ClassTypeInformation.MAP,
|
return new DefaultCassandraColumnType(ClassTypeInformation.MAP,
|
||||||
DataTypes.mapOf(keyType.getDataType(), valueType.getDataType()), keyType, valueType);
|
() -> DataTypes.mapOf(keyType.getDataType(), valueType.getDataType()), keyType, valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public interface ColumnTypeResolver {
|
|||||||
* @return
|
* @return
|
||||||
* @see CassandraType
|
* @see CassandraType
|
||||||
* @see CassandraPersistentProperty
|
* @see CassandraPersistentProperty
|
||||||
|
* @throws org.springframework.dao.InvalidDataAccessApiUsageException
|
||||||
*/
|
*/
|
||||||
default CassandraColumnType resolve(CassandraPersistentProperty property) {
|
default CassandraColumnType resolve(CassandraPersistentProperty property) {
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ public interface ColumnTypeResolver {
|
|||||||
* @return
|
* @return
|
||||||
* @see org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder
|
* @see org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder
|
||||||
* @see CassandraCustomConversions
|
* @see CassandraCustomConversions
|
||||||
|
* @throws org.springframework.dao.InvalidDataAccessApiUsageException
|
||||||
*/
|
*/
|
||||||
CassandraColumnType resolve(TypeInformation<?> typeInformation);
|
CassandraColumnType resolve(TypeInformation<?> typeInformation);
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ public interface ColumnTypeResolver {
|
|||||||
* @return
|
* @return
|
||||||
* @see CassandraType
|
* @see CassandraType
|
||||||
* @see CassandraPersistentProperty
|
* @see CassandraPersistentProperty
|
||||||
|
* @throws org.springframework.dao.InvalidDataAccessApiUsageException
|
||||||
*/
|
*/
|
||||||
CassandraColumnType resolve(CassandraType annotation);
|
CassandraColumnType resolve(CassandraType annotation);
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.convert;
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
|
import org.springframework.data.util.Lazy;
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
import com.datastax.oss.driver.api.core.type.DataType;
|
||||||
@@ -31,16 +33,23 @@ import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
|||||||
*/
|
*/
|
||||||
class DefaultCassandraColumnType extends DefaultColumnType implements CassandraColumnType {
|
class DefaultCassandraColumnType extends DefaultColumnType implements CassandraColumnType {
|
||||||
|
|
||||||
private final DataType dataType;
|
private final Lazy<DataType> dataType;
|
||||||
|
|
||||||
DefaultCassandraColumnType(Class<?> type, DataType dataType, ColumnType... parameters) {
|
DefaultCassandraColumnType(Class<?> type, DataType dataType, ColumnType... parameters) {
|
||||||
this(ClassTypeInformation.from(type), dataType, parameters);
|
this(ClassTypeInformation.from(type), dataType, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefaultCassandraColumnType(TypeInformation<?> typeInformation, Supplier<DataType> dataType,
|
||||||
|
ColumnType... parameters) {
|
||||||
|
super(typeInformation, parameters);
|
||||||
|
|
||||||
|
this.dataType = Lazy.of(dataType);
|
||||||
|
}
|
||||||
|
|
||||||
DefaultCassandraColumnType(TypeInformation<?> typeInformation, DataType dataType, ColumnType... parameters) {
|
DefaultCassandraColumnType(TypeInformation<?> typeInformation, DataType dataType, ColumnType... parameters) {
|
||||||
super(typeInformation, parameters);
|
super(typeInformation, parameters);
|
||||||
|
|
||||||
this.dataType = dataType;
|
this.dataType = Lazy.of(dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -48,7 +57,7 @@ class DefaultCassandraColumnType extends DefaultColumnType implements CassandraC
|
|||||||
* @see org.springframework.data.cassandra.core.convert.CassandraColumnType#getDataType()
|
* @see org.springframework.data.cassandra.core.convert.CassandraColumnType#getDataType()
|
||||||
*/
|
*/
|
||||||
public DataType getDataType() {
|
public DataType getDataType() {
|
||||||
return dataType;
|
return dataType.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -20,30 +20,39 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder;
|
import org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraType.Name;
|
||||||
import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
|
import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
|
||||||
import org.springframework.data.convert.CustomConversions;
|
import org.springframework.data.convert.CustomConversions;
|
||||||
import org.springframework.data.mapping.MappingException;
|
import org.springframework.data.mapping.MappingException;
|
||||||
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
|
import org.springframework.data.util.Lazy;
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||||
import com.datastax.oss.driver.api.core.detach.AttachmentPoint;
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
import com.datastax.oss.driver.api.core.type.DataType;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
import com.datastax.oss.driver.api.core.type.DataTypes;
|
||||||
import com.datastax.oss.driver.api.core.type.ListType;
|
import com.datastax.oss.driver.api.core.type.ListType;
|
||||||
import com.datastax.oss.driver.api.core.type.MapType;
|
import com.datastax.oss.driver.api.core.type.MapType;
|
||||||
import com.datastax.oss.driver.api.core.type.SetType;
|
import com.datastax.oss.driver.api.core.type.SetType;
|
||||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||||
|
import com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
|
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||||
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
|
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
|
||||||
@@ -56,20 +65,64 @@ import com.datastax.oss.driver.api.core.type.reflect.GenericType;
|
|||||||
*/
|
*/
|
||||||
class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
||||||
|
|
||||||
private final CassandraMappingContext mappingContext;
|
private final Log log = LogFactory.getLog(getClass());
|
||||||
private final UserTypeResolver userTypeResolver;
|
|
||||||
private final CodecRegistry codecRegistry;
|
|
||||||
private CustomConversions customConversions;
|
|
||||||
|
|
||||||
public DefaultColumnTypeResolver(CassandraMappingContext mappingContext) {
|
private final MappingContext<? extends CassandraPersistentEntity<?>, ? extends CassandraPersistentProperty> mappingContext;
|
||||||
|
private final UserTypeResolver userTypeResolver;
|
||||||
|
private final Supplier<CodecRegistry> codecRegistry;
|
||||||
|
private final Supplier<CustomConversions> customConversions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link DefaultColumnTypeResolver}.
|
||||||
|
*
|
||||||
|
* @param mappingContext
|
||||||
|
* @param userTypeResolver
|
||||||
|
* @param codecRegistry
|
||||||
|
* @param customConversions
|
||||||
|
*/
|
||||||
|
public DefaultColumnTypeResolver(
|
||||||
|
MappingContext<? extends CassandraPersistentEntity<?>, ? extends CassandraPersistentProperty> mappingContext,
|
||||||
|
UserTypeResolver userTypeResolver, Supplier<CodecRegistry> codecRegistry,
|
||||||
|
Supplier<CustomConversions> customConversions) {
|
||||||
this.mappingContext = mappingContext;
|
this.mappingContext = mappingContext;
|
||||||
this.userTypeResolver = mappingContext.getUserTypeResolver();
|
this.userTypeResolver = userTypeResolver;
|
||||||
this.codecRegistry = mappingContext.getCodecRegistry();
|
this.codecRegistry = codecRegistry;
|
||||||
this.customConversions = mappingContext.getCustomConversions();
|
this.customConversions = customConversions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCustomConversions(CustomConversions customConversions) {
|
@Override
|
||||||
this.customConversions = customConversions;
|
public CassandraColumnType resolve(CassandraPersistentProperty property) {
|
||||||
|
|
||||||
|
Assert.notNull(property, "Property must not be null");
|
||||||
|
|
||||||
|
if (property.isAnnotationPresent(CassandraType.class)) {
|
||||||
|
|
||||||
|
CassandraType annotation = property.getRequiredAnnotation(CassandraType.class);
|
||||||
|
|
||||||
|
if (annotation.type() == Name.UDT && StringUtils.isEmpty(annotation.userTypeName())) {
|
||||||
|
throw new InvalidDataAccessApiUsageException(
|
||||||
|
String.format("Expected user type name in property ['%s'] of type ['%s'] in entity [%s]",
|
||||||
|
property.getName(), property.getType(), property.getOwner().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((annotation.type() == Name.LIST || annotation.type() == Name.SET) && annotation.typeArguments().length != 1) {
|
||||||
|
|
||||||
|
throw new InvalidDataAccessApiUsageException(String.format(
|
||||||
|
"Expected [%d] type arguments for property ['%s'] of type ['%s'] in entity [%s]; actual was [%d]", 1,
|
||||||
|
property.getName(), property.getType(), property.getOwner().getName(), annotation.typeArguments().length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotation.type() == Name.MAP && annotation.typeArguments().length != 2) {
|
||||||
|
|
||||||
|
throw new InvalidDataAccessApiUsageException(String.format(
|
||||||
|
"Expected [%d] type arguments for property ['%s'] of type ['%s'] in entity [%s]; actual was [%d]", 2,
|
||||||
|
property.getName(), property.getType(), property.getOwner().getName(), annotation.typeArguments().length));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(property.getTypeInformation());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -79,9 +132,7 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
@Override
|
@Override
|
||||||
public CassandraColumnType resolve(TypeInformation<?> typeInformation) {
|
public CassandraColumnType resolve(TypeInformation<?> typeInformation) {
|
||||||
|
|
||||||
Optional<Class<?>> writeTarget = customConversions.getCustomWriteTarget(typeInformation.getType());
|
return getCustomWriteTarget(typeInformation).map(it -> {
|
||||||
|
|
||||||
return writeTarget.map(it -> {
|
|
||||||
return createCassandraTypeDescriptor(tryResolve(it), ClassTypeInformation.from(it));
|
return createCassandraTypeDescriptor(tryResolve(it), ClassTypeInformation.from(it));
|
||||||
}).orElseGet(() -> {
|
}).orElseGet(() -> {
|
||||||
|
|
||||||
@@ -93,17 +144,29 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<Class<?>> getCustomWriteTarget(TypeInformation<?> typeInformation) {
|
||||||
|
return customConversions.get().getCustomWriteTarget(typeInformation.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private DataType tryResolve(Class<?> type) {
|
private DataType tryResolve(Class<?> type) {
|
||||||
|
|
||||||
if (TupleValue.class.isAssignableFrom(type)) {
|
if (TupleValue.class.isAssignableFrom(type)) {
|
||||||
return DataTypes.tupleOf();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UdtValue.class.isAssignableFrom(type)) {
|
if (UdtValue.class.isAssignableFrom(type)) {
|
||||||
return UnknownUserDefinedType.INSTANCE;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return codecRegistry.codecFor(type).getCqlType();
|
try {
|
||||||
|
return getCodecRegistry().codecFor(type).getCqlType();
|
||||||
|
} catch (CodecNotFoundException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(String.format("Cannot resolve Codec for %s", type.getName()), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -113,7 +176,7 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
@Override
|
@Override
|
||||||
public CassandraColumnType resolve(CassandraType annotation) {
|
public CassandraColumnType resolve(CassandraType annotation) {
|
||||||
|
|
||||||
CassandraType.Name type = annotation.type();
|
Name type = annotation.type();
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MAP:
|
case MAP:
|
||||||
@@ -130,11 +193,10 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
case SET:
|
case SET:
|
||||||
assertTypeArguments(annotation.typeArguments().length, 1);
|
assertTypeArguments(annotation.typeArguments().length, 1);
|
||||||
|
|
||||||
DataType componentType = annotation.typeArguments()[0] == CassandraType.Name.UDT
|
DataType componentType = annotation.typeArguments()[0] == Name.UDT ? getUserType(annotation.userTypeName())
|
||||||
? getUserType(annotation.userTypeName())
|
|
||||||
: CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]);
|
: CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]);
|
||||||
|
|
||||||
if (type == CassandraType.Name.SET) {
|
if (type == Name.SET) {
|
||||||
return ColumnType.setOf(createCassandraTypeDescriptor(componentType));
|
return ColumnType.setOf(createCassandraTypeDescriptor(componentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +210,11 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
return ColumnType.tupleOf(DataTypes.tupleOf(dataTypes));
|
return ColumnType.tupleOf(DataTypes.tupleOf(dataTypes));
|
||||||
case UDT:
|
case UDT:
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(annotation.userTypeName())) {
|
||||||
|
throw new InvalidDataAccessApiUsageException(
|
||||||
|
"Cannot resolve user type for @CassandraType(type=UDT) without userTypeName");
|
||||||
|
}
|
||||||
|
|
||||||
return createCassandraTypeDescriptor(getUserType(annotation.userTypeName()));
|
return createCassandraTypeDescriptor(getUserType(annotation.userTypeName()));
|
||||||
default:
|
default:
|
||||||
return createCassandraTypeDescriptor(CassandraSimpleTypeHolder.getDataTypeFor(type));
|
return createCassandraTypeDescriptor(CassandraSimpleTypeHolder.getDataTypeFor(type));
|
||||||
@@ -165,9 +232,7 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
|
|
||||||
ClassTypeInformation<?> typeInformation = ClassTypeInformation.from(value.getClass());
|
ClassTypeInformation<?> typeInformation = ClassTypeInformation.from(value.getClass());
|
||||||
|
|
||||||
Optional<Class<?>> writeTarget = customConversions.getCustomWriteTarget(typeInformation.getType());
|
return getCustomWriteTarget(typeInformation).map(it -> {
|
||||||
|
|
||||||
return writeTarget.map(it -> {
|
|
||||||
return (ColumnType) createCassandraTypeDescriptor(tryResolve(it), typeInformation);
|
return (ColumnType) createCassandraTypeDescriptor(tryResolve(it), typeInformation);
|
||||||
}).orElseGet(() -> {
|
}).orElseGet(() -> {
|
||||||
|
|
||||||
@@ -195,7 +260,7 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
return ColumnType.tupleOf(((TupleValue) value).getType());
|
return ColumnType.tupleOf(((TupleValue) value).getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(typeInformation);
|
CassandraPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(typeInformation);
|
||||||
|
|
||||||
if (persistentEntity != null) {
|
if (persistentEntity != null) {
|
||||||
|
|
||||||
@@ -213,11 +278,12 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
|
|
||||||
private CassandraColumnType createCassandraTypeDescriptor(DataType dataType) {
|
private CassandraColumnType createCassandraTypeDescriptor(DataType dataType) {
|
||||||
|
|
||||||
GenericType<Object> javaType = codecRegistry.codecFor(dataType).getJavaType();
|
GenericType<Object> javaType = getCodecRegistry().codecFor(dataType).getJavaType();
|
||||||
return ColumnType.create(javaType.getRawType(), dataType);
|
return ColumnType.create(javaType.getRawType(), dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CassandraColumnType createCassandraTypeDescriptor(DataType dataType, TypeInformation<?> typeInformation) {
|
private CassandraColumnType createCassandraTypeDescriptor(@Nullable DataType dataType,
|
||||||
|
TypeInformation<?> typeInformation) {
|
||||||
|
|
||||||
if (typeInformation.isCollectionLike() || typeInformation.isMap()) {
|
if (typeInformation.isCollectionLike() || typeInformation.isMap()) {
|
||||||
|
|
||||||
@@ -277,6 +343,10 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dataType == null) {
|
||||||
|
return new UnresolvableCassandraType(typeInformation);
|
||||||
|
}
|
||||||
|
|
||||||
return new DefaultCassandraColumnType(typeInformation, dataType);
|
return new DefaultCassandraColumnType(typeInformation, dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,12 +365,12 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
resolve(typeInformation.getRequiredMapValueType()));
|
resolve(typeInformation.getRequiredMapValueType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(typeInformation);
|
CassandraPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(typeInformation);
|
||||||
|
|
||||||
if (persistentEntity != null) {
|
if (persistentEntity != null) {
|
||||||
|
|
||||||
if (persistentEntity.isUserDefinedType()) {
|
if (persistentEntity.isUserDefinedType()) {
|
||||||
return new DefaultCassandraColumnType(typeInformation, persistentEntity.getUserType());
|
return new DefaultCassandraColumnType(typeInformation, getUserType(persistentEntity));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (persistentEntity.isTupleType()) {
|
if (persistentEntity.isTupleType()) {
|
||||||
@@ -316,26 +386,47 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
return new UnresolvableCassandraType(typeInformation);
|
return new UnresolvableCassandraType(typeInformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DefaultCassandraColumnType(typeInformation, tryResolve(typeInformation.getType()));
|
DataType dataType = tryResolve(typeInformation.getType());
|
||||||
|
if (dataType == null) {
|
||||||
|
return new UnresolvableCassandraType(typeInformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultCassandraColumnType(typeInformation, dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataType getUserType(CassandraPersistentEntity<?> persistentEntity) {
|
||||||
|
|
||||||
|
CqlIdentifier identifier = persistentEntity.getTableName();
|
||||||
|
com.datastax.oss.driver.api.core.type.UserDefinedType userType = userTypeResolver.resolveType(identifier);
|
||||||
|
|
||||||
|
if (userType == null) {
|
||||||
|
throw new MappingException(String.format("User type [%s] not found", identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
return userType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> resolveToJavaType(DataType dataType) {
|
private Class<?> resolveToJavaType(DataType dataType) {
|
||||||
TypeCodec<Object> codec = codecRegistry.codecFor(dataType);
|
TypeCodec<Object> codec = getCodecRegistry().codecFor(dataType);
|
||||||
return codec.getJavaType().getRawType();
|
return codec.getJavaType().getRawType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CodecRegistry getCodecRegistry() {
|
||||||
|
return codecRegistry.get();
|
||||||
|
}
|
||||||
|
|
||||||
private DataType getUserType(String userTypeName) {
|
private DataType getUserType(String userTypeName) {
|
||||||
|
|
||||||
UserDefinedType type = userTypeResolver.resolveType(CqlIdentifier.fromCql(userTypeName));
|
UserDefinedType type = userTypeResolver.resolveType(CqlIdentifier.fromCql(userTypeName));
|
||||||
|
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new IllegalArgumentException(String.format("Cannot resolve UserDefinedType for [%s]", userTypeName));
|
throw new MappingException(String.format("Cannot resolve UserDefinedType for [%s]", userTypeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTypeArguments(int args, int expected) {
|
private static void assertTypeArguments(int args, int expected) {
|
||||||
|
|
||||||
if (args != expected) {
|
if (args != expected) {
|
||||||
throw new InvalidDataAccessApiUsageException(
|
throw new InvalidDataAccessApiUsageException(
|
||||||
@@ -343,147 +434,10 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UnknownUserDefinedType implements com.datastax.oss.driver.api.core.type.UserDefinedType {
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
UnknownUserDefinedType() {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#getKeyspace()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public CqlIdentifier getKeyspace() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#getName()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public CqlIdentifier getName() {
|
|
||||||
return CqlIdentifier.fromCql("unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#isFrozen()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isFrozen() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#getFieldNames()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<CqlIdentifier> getFieldNames() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#firstIndexOf(com.datastax.oss.driver.api.core.CqlIdentifier)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int firstIndexOf(CqlIdentifier id) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#firstIndexOf(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int firstIndexOf(String name) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#getFieldTypes()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<DataType> getFieldTypes() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#copy(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public com.datastax.oss.driver.api.core.type.UserDefinedType copy(boolean newFrozen) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#newValue()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public UdtValue newValue() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#newValue(java.lang.Object[])
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public UdtValue newValue(Object... fields) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.type.UserDefinedType#getAttachmentPoint()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AttachmentPoint getAttachmentPoint() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.detach.Detachable#isDetached()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isDetached() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see com.datastax.oss.driver.api.core.detach.Detachable#attach(com.datastax.oss.driver.api.core.detach.AttachmentPoint)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void attach(AttachmentPoint attachmentPoint) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UnresolvableCassandraType extends DefaultCassandraColumnType {
|
static class UnresolvableCassandraType extends DefaultCassandraColumnType {
|
||||||
|
|
||||||
public UnresolvableCassandraType(TypeInformation<?> type, ColumnType... parameters) {
|
public UnresolvableCassandraType(TypeInformation<?> type, ColumnType... parameters) {
|
||||||
super(type, null, parameters);
|
super(type, Lazy.empty(), parameters);
|
||||||
}
|
|
||||||
|
|
||||||
public UnresolvableCassandraType(Class<?> type, ColumnType... parameters) {
|
|
||||||
super(type, null, parameters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -495,4 +449,5 @@ class DefaultColumnTypeResolver implements ColumnTypeResolver {
|
|||||||
throw new MappingException(String.format("Cannot resolve DataType for %s", getType().getName()));
|
throw new MappingException(String.format("Cannot resolve DataType for %s", getType().getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedParameterizedType;
|
import java.lang.reflect.AnnotatedParameterizedType;
|
||||||
@@ -27,6 +27,9 @@ import java.util.function.BiConsumer;
|
|||||||
|
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Indexed;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.SASI;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.NonTokenizingAnalyzed;
|
import org.springframework.data.cassandra.core.mapping.SASI.NonTokenizingAnalyzed;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.Normalization;
|
import org.springframework.data.cassandra.core.mapping.SASI.Normalization;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.StandardAnalyzed;
|
import org.springframework.data.cassandra.core.mapping.SASI.StandardAnalyzed;
|
||||||
@@ -43,7 +43,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity
|
|||||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||||
import org.springframework.data.cassandra.core.mapping.MapId;
|
import org.springframework.data.cassandra.core.mapping.MapId;
|
||||||
import org.springframework.data.cassandra.core.mapping.MapIdentifiable;
|
import org.springframework.data.cassandra.core.mapping.MapIdentifiable;
|
||||||
import org.springframework.data.convert.CustomConversions;
|
import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
|
||||||
import org.springframework.data.mapping.MappingException;
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.PreferredConstructor;
|
import org.springframework.data.mapping.PreferredConstructor;
|
||||||
@@ -91,6 +91,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
|||||||
|
|
||||||
private final CassandraMappingContext mappingContext;
|
private final CassandraMappingContext mappingContext;
|
||||||
|
|
||||||
|
private CodecRegistry codecRegistry;
|
||||||
|
|
||||||
|
private UserTypeResolver userTypeResolver;
|
||||||
|
|
||||||
private @Nullable ClassLoader beanClassLoader;
|
private @Nullable ClassLoader beanClassLoader;
|
||||||
|
|
||||||
private SpELContext spELContext;
|
private SpELContext spELContext;
|
||||||
@@ -107,8 +111,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
|||||||
CassandraCustomConversions conversions = new CassandraCustomConversions(Collections.emptyList());
|
CassandraCustomConversions conversions = new CassandraCustomConversions(Collections.emptyList());
|
||||||
|
|
||||||
this.mappingContext = newDefaultMappingContext(conversions);
|
this.mappingContext = newDefaultMappingContext(conversions);
|
||||||
|
this.codecRegistry = mappingContext.getCodecRegistry();
|
||||||
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
|
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
|
||||||
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext);
|
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext,
|
||||||
|
userTypeName -> getUserTypeResolver().resolveType(userTypeName), this::getCodecRegistry,
|
||||||
|
this::getCustomConversions);
|
||||||
this.setCustomConversions(conversions);
|
this.setCustomConversions(conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,8 +131,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
|||||||
Assert.notNull(mappingContext, "CassandraMappingContext must not be null");
|
Assert.notNull(mappingContext, "CassandraMappingContext must not be null");
|
||||||
|
|
||||||
this.mappingContext = mappingContext;
|
this.mappingContext = mappingContext;
|
||||||
|
this.codecRegistry = mappingContext.getCodecRegistry();
|
||||||
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
|
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
|
||||||
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext);
|
this.cassandraTypeResolver = new DefaultColumnTypeResolver(mappingContext,
|
||||||
|
userTypeName -> getUserTypeResolver().resolveType(userTypeName), this::getCodecRegistry,
|
||||||
|
this::getCustomConversions);
|
||||||
this.setCustomConversions(mappingContext.getCustomConversions());
|
this.setCustomConversions(mappingContext.getCustomConversions());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,15 +153,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
|||||||
return mappingContext;
|
return mappingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCustomConversions(CustomConversions conversions) {
|
|
||||||
super.setCustomConversions(conversions);
|
|
||||||
|
|
||||||
if (this.cassandraTypeResolver != null) {
|
|
||||||
this.cassandraTypeResolver.setCustomConversions(conversions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||||
*/
|
*/
|
||||||
@@ -169,11 +170,63 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TypeCodec<Object> getCodec(CassandraPersistentProperty property) {
|
private TypeCodec<Object> getCodec(CassandraPersistentProperty property) {
|
||||||
return getCodecRegistry().codecFor(getMappingContext().getDataType(property));
|
return getCodecRegistry().codecFor(cassandraTypeResolver.resolve(property).getDataType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodecRegistry getCodecRegistry() {
|
/**
|
||||||
return getMappingContext().getCodecRegistry();
|
* Sets the {@link CodecRegistry}.
|
||||||
|
*
|
||||||
|
* @param codecRegistry must not be {@literal null}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public void setCodecRegistry(CodecRegistry codecRegistry) {
|
||||||
|
|
||||||
|
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
||||||
|
|
||||||
|
this.codecRegistry = codecRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configured {@link CodecRegistry}.
|
||||||
|
*
|
||||||
|
* @return the configured {@link CodecRegistry}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CodecRegistry getCodecRegistry() {
|
||||||
|
|
||||||
|
if (this.codecRegistry == null) {
|
||||||
|
return mappingContext.getCodecRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.codecRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link UserTypeResolver}.
|
||||||
|
*
|
||||||
|
* @param userTypeResolver must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public void setUserTypeResolver(UserTypeResolver userTypeResolver) {
|
||||||
|
|
||||||
|
Assert.notNull(userTypeResolver, "UserTypeResolver must not be null");
|
||||||
|
|
||||||
|
this.userTypeResolver = userTypeResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configured {@link UserTypeResolver}.
|
||||||
|
*
|
||||||
|
* @return the configured {@link UserTypeResolver}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public UserTypeResolver getUserTypeResolver() {
|
||||||
|
|
||||||
|
if (this.userTypeResolver == null) {
|
||||||
|
return this.mappingContext.getUserTypeResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
return userTypeResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -0,0 +1,383 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
|
import static org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.UserTypeResolver;
|
||||||
|
import org.springframework.data.convert.CustomConversions;
|
||||||
|
import org.springframework.data.mapping.MappingException;
|
||||||
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
|
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||||
|
import com.datastax.oss.driver.api.core.detach.AttachmentPoint;
|
||||||
|
import com.datastax.oss.driver.api.core.type.DataType;
|
||||||
|
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||||
|
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for Cassandra Schema objects such as user-defined types, tables and indexes.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @since 3.0
|
||||||
|
* @see CreateUserTypeSpecification
|
||||||
|
* @see CreateTableSpecification
|
||||||
|
* @see CreateIndexSpecification
|
||||||
|
* @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext
|
||||||
|
*/
|
||||||
|
public class SchemaFactory {
|
||||||
|
|
||||||
|
private final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
|
||||||
|
|
||||||
|
private final ColumnTypeResolver typeResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SchemaFactory} given {@link CassandraConverter}.
|
||||||
|
*
|
||||||
|
* @param converter must not be null.
|
||||||
|
*/
|
||||||
|
public SchemaFactory(CassandraConverter converter) {
|
||||||
|
|
||||||
|
Assert.notNull(converter, "CassandraConverter must not be null");
|
||||||
|
|
||||||
|
this.mappingContext = converter.getMappingContext();
|
||||||
|
this.typeResolver = new DefaultColumnTypeResolver(mappingContext, ShallowUserTypeResolver.INSTANCE,
|
||||||
|
converter::getCodecRegistry, converter::getCustomConversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SchemaFactory} given {@link MappingContext}, {@link CustomConversions} and
|
||||||
|
* {@link CodecRegistry}.
|
||||||
|
*
|
||||||
|
* @param mappingContext must not be null.
|
||||||
|
* @param customConversions must not be null.
|
||||||
|
* @param codecRegistry must not be null.
|
||||||
|
*/
|
||||||
|
public SchemaFactory(
|
||||||
|
MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext,
|
||||||
|
CustomConversions customConversions, CodecRegistry codecRegistry) {
|
||||||
|
|
||||||
|
Assert.notNull(mappingContext, "MappingContext must not be null");
|
||||||
|
Assert.notNull(customConversions, "CustomConversions must not be null");
|
||||||
|
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
||||||
|
|
||||||
|
this.mappingContext = mappingContext;
|
||||||
|
this.typeResolver = new DefaultColumnTypeResolver(mappingContext, ShallowUserTypeResolver.INSTANCE,
|
||||||
|
() -> codecRegistry, () -> customConversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link CreateTableSpecification} for the given entity, including all mapping information.
|
||||||
|
*
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @return the {@link CreateTableSpecification} derived from {@code entityType}.
|
||||||
|
*/
|
||||||
|
public CreateTableSpecification getCreateTableSpecificationFor(Class<?> entityType) {
|
||||||
|
|
||||||
|
Assert.notNull(entityType, "Entity type must not be null");
|
||||||
|
|
||||||
|
return getCreateTableSpecificationFor(mappingContext.getRequiredPersistentEntity(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link CreateTableSpecification} for the given entity, including all mapping information.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @return the {@link CreateTableSpecification} derived from {@link CassandraPersistentEntity}.
|
||||||
|
*/
|
||||||
|
public CreateTableSpecification getCreateTableSpecificationFor(CassandraPersistentEntity<?> entity) {
|
||||||
|
|
||||||
|
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||||
|
|
||||||
|
return getCreateTableSpecificationFor(entity, entity.getTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link CreateTableSpecification} for the given entity using {@link CqlIdentifier table name}, including
|
||||||
|
* all mapping information.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param tableName must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
public CreateTableSpecification getCreateTableSpecificationFor(CassandraPersistentEntity<?> entity,
|
||||||
|
CqlIdentifier tableName) {
|
||||||
|
|
||||||
|
Assert.notNull(tableName, "Table name must not be null");
|
||||||
|
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||||
|
|
||||||
|
CreateTableSpecification specification = createTable(tableName);
|
||||||
|
|
||||||
|
for (CassandraPersistentProperty property : entity) {
|
||||||
|
|
||||||
|
if (property.isCompositePrimaryKey()) {
|
||||||
|
|
||||||
|
CassandraPersistentEntity<?> primaryKeyEntity = mappingContext
|
||||||
|
.getRequiredPersistentEntity(property.getRawType());
|
||||||
|
|
||||||
|
for (CassandraPersistentProperty primaryKeyProperty : primaryKeyEntity) {
|
||||||
|
|
||||||
|
DataType dataType = getDataType(primaryKeyProperty);
|
||||||
|
|
||||||
|
if (primaryKeyProperty.isPartitionKeyColumn()) {
|
||||||
|
specification.partitionKeyColumn(primaryKeyProperty.getRequiredColumnName(), dataType);
|
||||||
|
} else { // cluster column
|
||||||
|
specification.clusteredKeyColumn(primaryKeyProperty.getRequiredColumnName(), dataType,
|
||||||
|
primaryKeyProperty.getPrimaryKeyOrdering());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DataType type = UserTypeUtil.potentiallyFreeze(getDataType(property));
|
||||||
|
|
||||||
|
if (property.isIdProperty() || property.isPartitionKeyColumn()) {
|
||||||
|
specification.partitionKeyColumn(property.getRequiredColumnName(), type);
|
||||||
|
} else if (property.isClusterKeyColumn()) {
|
||||||
|
specification.clusteredKeyColumn(property.getRequiredColumnName(), type, property.getPrimaryKeyOrdering());
|
||||||
|
} else {
|
||||||
|
specification.column(property.getRequiredColumnName(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (specification.getPartitionKeyColumns().isEmpty()) {
|
||||||
|
throw new MappingException(String.format("No partition key columns found in entity [%s]", entity.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return specification;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataType getDataType(CassandraPersistentProperty property) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return typeResolver.resolve(property).getDataType();
|
||||||
|
} catch (MappingException e) {
|
||||||
|
|
||||||
|
throw new MappingException(String.format(
|
||||||
|
"Cannot resolve DataType for type [%s] for property [%s] in entity [%s]; Consider registering a Converter or annotating the property with @CassandraType.",
|
||||||
|
property.getType(), property.getName(), property.getOwner().getName()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@link CreateIndexSpecification index specifications} derived from {@link CassandraPersistentEntity}.
|
||||||
|
*
|
||||||
|
* @param entityType must not be {@literal null}.
|
||||||
|
* @return the {@link CreateTableSpecification} derived from {@code entityType}.
|
||||||
|
*/
|
||||||
|
public List<CreateIndexSpecification> getCreateIndexSpecificationsFor(Class<?> entityType) {
|
||||||
|
|
||||||
|
Assert.notNull(entityType, "Entity type must not be null");
|
||||||
|
|
||||||
|
return getCreateIndexSpecificationsFor(mappingContext.getRequiredPersistentEntity(entityType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@link CreateIndexSpecification index specifications} derived from {@link CassandraPersistentEntity}.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public List<CreateIndexSpecification> getCreateIndexSpecificationsFor(CassandraPersistentEntity<?> entity) {
|
||||||
|
|
||||||
|
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||||
|
|
||||||
|
return getCreateIndexSpecificationsFor(entity, entity.getTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@link CreateIndexSpecification index specifications} derived from {@link CassandraPersistentEntity} using
|
||||||
|
* {@link CqlIdentifier table name}.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
* @param tableName must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public List<CreateIndexSpecification> getCreateIndexSpecificationsFor(CassandraPersistentEntity<?> entity,
|
||||||
|
CqlIdentifier tableName) {
|
||||||
|
|
||||||
|
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||||
|
Assert.notNull(tableName, "Table name must not be null");
|
||||||
|
|
||||||
|
List<CreateIndexSpecification> indexes = new ArrayList<>();
|
||||||
|
|
||||||
|
for (CassandraPersistentProperty property : entity) {
|
||||||
|
if (property.isCompositePrimaryKey()) {
|
||||||
|
indexes.addAll(getCreateIndexSpecificationsFor(mappingContext.getRequiredPersistentEntity(property)));
|
||||||
|
} else {
|
||||||
|
indexes.addAll(IndexSpecificationFactory.createIndexSpecifications(property));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes.forEach(it -> it.tableName(entity.getTableName()));
|
||||||
|
|
||||||
|
return indexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link CreateUserTypeSpecification} for the given entity, including all mapping information.
|
||||||
|
*
|
||||||
|
* @param entity must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public CreateUserTypeSpecification getCreateUserTypeSpecificationFor(CassandraPersistentEntity<?> entity) {
|
||||||
|
|
||||||
|
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||||
|
|
||||||
|
CreateUserTypeSpecification specification = CreateUserTypeSpecification.createType(entity.getTableName());
|
||||||
|
|
||||||
|
for (CassandraPersistentProperty property : entity) {
|
||||||
|
// Use frozen literal to not resolve types from Cassandra; At this stage, they might be not created yet.
|
||||||
|
specification.field(property.getRequiredColumnName(), UserTypeUtil.potentiallyFreeze(getDataType(property)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (specification.getFields().isEmpty()) {
|
||||||
|
throw new MappingException(String.format("No fields in user type [%s]", entity.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return specification;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ShallowUserTypeResolver implements UserTypeResolver {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDefinedType resolveType(CqlIdentifier typeName) {
|
||||||
|
return new ShallowUserDefinedType(typeName, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ShallowUserDefinedType implements com.datastax.oss.driver.api.core.type.UserDefinedType {
|
||||||
|
|
||||||
|
private final CqlIdentifier name;
|
||||||
|
private final boolean frozen;
|
||||||
|
|
||||||
|
public ShallowUserDefinedType(String name, boolean frozen) {
|
||||||
|
this(CqlIdentifier.fromInternal(name), frozen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShallowUserDefinedType(CqlIdentifier name, boolean frozen) {
|
||||||
|
this.name = name;
|
||||||
|
this.frozen = frozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CqlIdentifier getKeyspace() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CqlIdentifier getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFrozen() {
|
||||||
|
return frozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CqlIdentifier> getFieldNames() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int firstIndexOf(CqlIdentifier id) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int firstIndexOf(String name) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DataType> getFieldTypes() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.datastax.oss.driver.api.core.type.UserDefinedType copy(boolean newFrozen) {
|
||||||
|
return new ShallowUserDefinedType(this.name, newFrozen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UdtValue newValue() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UdtValue newValue(@edu.umd.cs.findbugs.annotations.NonNull Object... fields) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AttachmentPoint getAttachmentPoint() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDetached() {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attach(@edu.umd.cs.findbugs.annotations.NonNull AttachmentPoint attachmentPoint) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This implementation should only be used internally, this is likely a driver bug");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o)
|
||||||
|
return true;
|
||||||
|
if (!(o instanceof com.datastax.oss.driver.api.core.type.UserDefinedType))
|
||||||
|
return false;
|
||||||
|
com.datastax.oss.driver.api.core.type.UserDefinedType that = (com.datastax.oss.driver.api.core.type.UserDefinedType) o;
|
||||||
|
return isFrozen() == that.isFrozen() && Objects.equals(getName(), that.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name, frozen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UDT(" + name.asCql(true) + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -169,7 +169,8 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
|
|
||||||
if (collection.isEmpty()) {
|
if (collection.isEmpty()) {
|
||||||
|
|
||||||
int protocolCode = field.getProperty().map(property -> getMappingContext().getDataType(property))
|
int protocolCode = field.getProperty()
|
||||||
|
.map(property -> getConverter().getColumnTypeResolver().resolve(property).getDataType())
|
||||||
.map(DataType::getProtocolCode).orElse(ProtocolConstants.DataType.LIST);
|
.map(DataType::getProtocolCode).orElse(ProtocolConstants.DataType.LIST);
|
||||||
|
|
||||||
if (protocolCode == ProtocolConstants.DataType.SET) {
|
if (protocolCode == ProtocolConstants.DataType.SET) {
|
||||||
@@ -203,7 +204,7 @@ public class UpdateMapper extends QueryMapper {
|
|||||||
|
|
||||||
if (field.getProperty().isPresent()) {
|
if (field.getProperty().isPresent()) {
|
||||||
|
|
||||||
DataType dataType = getMappingContext().getDataType(field.getProperty().get());
|
DataType dataType = getConverter().getColumnTypeResolver().resolve(field.getProperty().get()).getDataType();
|
||||||
|
|
||||||
if (dataType instanceof SetType && !(mappedValue instanceof Set)) {
|
if (dataType instanceof SetType && !(mappedValue instanceof Set)) {
|
||||||
Collection<Object> collection = new HashSet<>();
|
Collection<Object> collection = new HashSet<>();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -35,7 +35,6 @@ import org.springframework.util.Assert;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cassandra specific {@link BasicPersistentEntity} implementation that adds Cassandra specific metadata.
|
* Cassandra specific {@link BasicPersistentEntity} implementation that adds Cassandra specific metadata.
|
||||||
@@ -231,15 +230,6 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#getTupleType()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public TupleType getTupleType() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#isUserDefinedType()
|
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#isUserDefinedType()
|
||||||
*/
|
*/
|
||||||
@@ -248,12 +238,4 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity#getUserType()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public com.datastax.oss.driver.api.core.type.UserDefinedType getUserType() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,29 +15,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import static org.springframework.data.cassandra.core.mapping.CassandraType.*;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedParameterizedType;
|
import java.lang.reflect.AnnotatedParameterizedType;
|
||||||
import java.lang.reflect.AnnotatedType;
|
import java.lang.reflect.AnnotatedType;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.context.expression.BeanFactoryAccessor;
|
import org.springframework.context.expression.BeanFactoryAccessor;
|
||||||
import org.springframework.context.expression.BeanFactoryResolver;
|
import org.springframework.context.expression.BeanFactoryResolver;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
|
||||||
import org.springframework.data.cassandra.core.cql.Ordering;
|
import org.springframework.data.cassandra.core.cql.Ordering;
|
||||||
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
||||||
import org.springframework.data.cassandra.util.SpelUtils;
|
import org.springframework.data.cassandra.util.SpelUtils;
|
||||||
import org.springframework.data.mapping.Association;
|
import org.springframework.data.mapping.Association;
|
||||||
import org.springframework.data.mapping.MappingException;
|
|
||||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||||
import org.springframework.data.mapping.model.Property;
|
import org.springframework.data.mapping.model.Property;
|
||||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||||
@@ -50,9 +44,6 @@ import org.springframework.util.ClassUtils;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
|
||||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cassandra specific {@link org.springframework.data.mapping.model.AnnotationBasedPersistentProperty} implementation.
|
* Cassandra specific {@link org.springframework.data.mapping.model.AnnotationBasedPersistentProperty} implementation.
|
||||||
@@ -73,8 +64,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
|||||||
|
|
||||||
private @Nullable StandardEvaluationContext spelContext;
|
private @Nullable StandardEvaluationContext spelContext;
|
||||||
|
|
||||||
private final @Nullable UserTypeResolver userTypeResolver;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link BasicCassandraPersistentProperty}.
|
* Create a new {@link BasicCassandraPersistentProperty}.
|
||||||
*
|
*
|
||||||
@@ -85,23 +74,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
|||||||
public BasicCassandraPersistentProperty(Property property, CassandraPersistentEntity<?> owner,
|
public BasicCassandraPersistentProperty(Property property, CassandraPersistentEntity<?> owner,
|
||||||
SimpleTypeHolder simpleTypeHolder) {
|
SimpleTypeHolder simpleTypeHolder) {
|
||||||
|
|
||||||
this(property, owner, simpleTypeHolder, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link BasicCassandraPersistentProperty}.
|
|
||||||
*
|
|
||||||
* @param property the actual {@link Property} in the domain entity corresponding to this persistent entity.
|
|
||||||
* @param owner the containing object or {@link CassandraPersistentEntity} of this persistent property.
|
|
||||||
* @param simpleTypeHolder mapping of Java [simple|wrapper] types to Cassandra data types.
|
|
||||||
* @param userTypeResolver resolver for user-defined types.
|
|
||||||
*/
|
|
||||||
public BasicCassandraPersistentProperty(Property property, CassandraPersistentEntity<?> owner,
|
|
||||||
SimpleTypeHolder simpleTypeHolder, @Nullable UserTypeResolver userTypeResolver) {
|
|
||||||
|
|
||||||
super(property, owner, simpleTypeHolder);
|
super(property, owner, simpleTypeHolder);
|
||||||
|
|
||||||
this.userTypeResolver = userTypeResolver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -162,128 +135,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
|||||||
return annotation != null ? annotation.ordering() : null;
|
return annotation != null ? annotation.ordering() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#getDataType()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DataType getDataType() {
|
|
||||||
|
|
||||||
DataType dataType = findDataType();
|
|
||||||
|
|
||||||
if (dataType == null) {
|
|
||||||
throw new InvalidDataAccessApiUsageException(String.format(
|
|
||||||
"Unknown type [%s] for property [%s] in entity [%s]; only primitive types and Collections or Maps of primitive types are allowed",
|
|
||||||
getType(), getName(), getOwner().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DataType findDataType() {
|
|
||||||
|
|
||||||
CassandraType cassandraType = findAnnotation(CassandraType.class);
|
|
||||||
|
|
||||||
if (cassandraType != null) {
|
|
||||||
return getDataTypeFor(cassandraType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMap()) {
|
|
||||||
|
|
||||||
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
|
|
||||||
|
|
||||||
assertTypeArguments(args.size(), 2);
|
|
||||||
|
|
||||||
return DataTypes.mapOf(getDataTypeFor(args.get(0).getType()), getDataTypeFor(args.get(1).getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCollectionLike()) {
|
|
||||||
|
|
||||||
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
|
|
||||||
|
|
||||||
assertTypeArguments(args.size(), 1);
|
|
||||||
|
|
||||||
if (Set.class.isAssignableFrom(getType())) {
|
|
||||||
return DataTypes.setOf(getDataTypeFor(args.get(0).getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (List.class.isAssignableFrom(getType())) {
|
|
||||||
return DataTypes.listOf(getDataTypeFor(args.get(0).getType()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CassandraSimpleTypeHolder.getDataTypeFor(getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType getDataTypeFor(CassandraType annotation) {
|
|
||||||
|
|
||||||
Name type = annotation.type();
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case MAP:
|
|
||||||
assertTypeArguments(annotation.typeArguments().length, 2);
|
|
||||||
return DataTypes.mapOf(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]),
|
|
||||||
CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[1]));
|
|
||||||
case LIST:
|
|
||||||
assertTypeArguments(annotation.typeArguments().length, 1);
|
|
||||||
return annotation.typeArguments()[0] == Name.UDT
|
|
||||||
? DataTypes.listOf(getUserType(annotation))
|
|
||||||
: DataTypes.listOf(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]));
|
|
||||||
case SET:
|
|
||||||
assertTypeArguments(annotation.typeArguments().length, 1);
|
|
||||||
return annotation.typeArguments()[0] == Name.UDT
|
|
||||||
? DataTypes.setOf(getUserType(annotation))
|
|
||||||
: DataTypes.setOf(CassandraSimpleTypeHolder.getDataTypeFor(annotation.typeArguments()[0]));
|
|
||||||
case UDT:
|
|
||||||
return getUserType(annotation);
|
|
||||||
default:
|
|
||||||
return CassandraSimpleTypeHolder.getDataTypeFor(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType getUserType(CassandraType annotation) {
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(annotation.userTypeName())) {
|
|
||||||
throw new InvalidDataAccessApiUsageException(
|
|
||||||
String.format("Expected user type name in property ['%s'] of type ['%s'] in entity [%s]", getName(),
|
|
||||||
getType(), getOwner().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.state(this.userTypeResolver != null, "UserTypeResolver is null");
|
|
||||||
|
|
||||||
CqlIdentifier identifier = CqlIdentifier.fromCql(annotation.userTypeName());
|
|
||||||
|
|
||||||
UserDefinedType userType = this.userTypeResolver.resolveType(identifier);
|
|
||||||
|
|
||||||
if (userType == null) {
|
|
||||||
throw new MappingException(String.format("User type [%s] not found", identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
return userType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType getDataTypeFor(Class<?> javaType) {
|
|
||||||
|
|
||||||
DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(javaType);
|
|
||||||
|
|
||||||
if (dataType == null) {
|
|
||||||
throw new InvalidDataAccessApiUsageException(String.format(
|
|
||||||
"Only primitive types are allowed inside Collections for property [%1$s] of type ['%2$s'] in entity [%3$s]",
|
|
||||||
getName(), getType(), getOwner().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertTypeArguments(int args, int expected) {
|
|
||||||
|
|
||||||
if (args != expected) {
|
|
||||||
throw new InvalidDataAccessApiUsageException(String.format(
|
|
||||||
"Expected [%1$s] type arguments for property ['%2$s'] of type ['%3$s'] in entity [%4$s]; actual was [%5$d]",
|
|
||||||
expected, getName(), getType(), getOwner().getName(), args));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isCompositePrimaryKey()
|
* @see org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty#isCompositePrimaryKey()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,17 +16,9 @@
|
|||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
import org.springframework.data.mapping.MappingException;
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.data.util.Lazy;
|
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
|
||||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cassandra Tuple-specific {@link org.springframework.data.mapping.PersistentEntity} for a mapped tuples. Mapped tuples
|
* Cassandra Tuple-specific {@link org.springframework.data.mapping.PersistentEntity} for a mapped tuples. Mapped tuples
|
||||||
@@ -39,28 +31,15 @@ import com.datastax.oss.driver.api.core.type.TupleType;
|
|||||||
*/
|
*/
|
||||||
public class BasicCassandraPersistentTupleEntity<T> extends BasicCassandraPersistentEntity<T> {
|
public class BasicCassandraPersistentTupleEntity<T> extends BasicCassandraPersistentEntity<T> {
|
||||||
|
|
||||||
private final Lazy<TupleType> tupleType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link BasicCassandraPersistentTupleEntity} given {@link TypeInformation} and
|
* Creates a new {@link BasicCassandraPersistentTupleEntity} given {@link TypeInformation}.
|
||||||
* {@link TupleTypeFactory}.
|
|
||||||
*
|
*
|
||||||
* @param information must not be {@literal null}.
|
* @param information must not be {@literal null}.
|
||||||
* @param tupleTypeFactory must not be {@literal null}.
|
* @param tupleTypeFactory must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public BasicCassandraPersistentTupleEntity(TypeInformation<T> information, TupleTypeFactory tupleTypeFactory) {
|
public BasicCassandraPersistentTupleEntity(TypeInformation<T> information) {
|
||||||
|
|
||||||
super(information, CassandraPersistentTupleMetadataVerifier.INSTANCE, TuplePropertyComparator.INSTANCE);
|
super(information, CassandraPersistentTupleMetadataVerifier.INSTANCE, TuplePropertyComparator.INSTANCE);
|
||||||
|
|
||||||
Assert.notNull(tupleTypeFactory, "TupleTypeFactory must not be null");
|
|
||||||
|
|
||||||
this.tupleType = Lazy.of(() -> tupleTypeFactory.create(getTupleFieldDataTypes()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<DataType> getTupleFieldDataTypes() {
|
|
||||||
|
|
||||||
return StreamSupport.stream(spliterator(), false).sorted(TuplePropertyComparator.INSTANCE)
|
|
||||||
.map(CassandraPersistentProperty::getDataType).collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -82,14 +61,6 @@ public class BasicCassandraPersistentTupleEntity<T> extends BasicCassandraPersis
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity#getTupleType()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public TupleType getTupleType() {
|
|
||||||
return this.tupleType.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link CassandraPersistentProperty} comparator using to sort properties by their
|
* {@link CassandraPersistentProperty} comparator using to sort properties by their
|
||||||
* {@link CassandraPersistentProperty#getRequiredOrdinal()}.
|
* {@link CassandraPersistentProperty#getRequiredOrdinal()}.
|
||||||
|
|||||||
@@ -44,21 +44,7 @@ public class BasicCassandraPersistentTupleProperty extends BasicCassandraPersist
|
|||||||
public BasicCassandraPersistentTupleProperty(Property property, CassandraPersistentEntity<?> owner,
|
public BasicCassandraPersistentTupleProperty(Property property, CassandraPersistentEntity<?> owner,
|
||||||
SimpleTypeHolder simpleTypeHolder) {
|
SimpleTypeHolder simpleTypeHolder) {
|
||||||
|
|
||||||
this(property, owner, simpleTypeHolder, null);
|
super(property, owner, simpleTypeHolder);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link BasicCassandraPersistentTupleProperty}.
|
|
||||||
*
|
|
||||||
* @param property the actual {@link Property} in the domain entity corresponding to this persistent entity.
|
|
||||||
* @param owner the containing object or {@link CassandraPersistentEntity} of this persistent property.
|
|
||||||
* @param simpleTypeHolder mapping of Java [simple|wrapper] types to Cassandra data types.
|
|
||||||
* @param userTypeResolver resolver for user-defined types.
|
|
||||||
*/
|
|
||||||
public BasicCassandraPersistentTupleProperty(Property property, CassandraPersistentEntity<?> owner,
|
|
||||||
SimpleTypeHolder simpleTypeHolder, @Nullable UserTypeResolver userTypeResolver) {
|
|
||||||
|
|
||||||
super(property, owner, simpleTypeHolder, userTypeResolver);
|
|
||||||
|
|
||||||
this.ordinal = findOrdinal();
|
this.ordinal = findOrdinal();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import static org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification.*;
|
import java.util.Collection;
|
||||||
import static org.springframework.data.cassandra.core.mapping.CassandraType.*;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.*;
|
import java.util.HashSet;
|
||||||
import java.util.function.Supplier;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
@@ -27,32 +30,21 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
|
|||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
|
||||||
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
|
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
|
|
||||||
import org.springframework.data.convert.CustomConversions;
|
import org.springframework.data.convert.CustomConversions;
|
||||||
import org.springframework.data.mapping.MappingException;
|
|
||||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.Property;
|
import org.springframework.data.mapping.model.Property;
|
||||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||||
import org.springframework.data.util.Optionals;
|
import org.springframework.data.util.Optionals;
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
|
||||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
|
||||||
import com.datastax.oss.driver.api.core.detach.AttachmentPoint;
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
import com.datastax.oss.driver.api.core.type.DataType;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
|
||||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,15 +68,13 @@ public class CassandraMappingContext
|
|||||||
|
|
||||||
private @Nullable ClassLoader beanClassLoader;
|
private @Nullable ClassLoader beanClassLoader;
|
||||||
|
|
||||||
private CustomConversions customConversions = new CassandraCustomConversions(Collections.emptyList());
|
private @Deprecated CustomConversions customConversions = new CassandraCustomConversions(Collections.emptyList());
|
||||||
|
|
||||||
private Mapping mapping = new Mapping();
|
private Mapping mapping = new Mapping();
|
||||||
|
|
||||||
private TupleTypeFactory tupleTypeFactory = SimpleTupleTypeFactory.DEFAULT;
|
private @Deprecated @Nullable UserTypeResolver userTypeResolver;
|
||||||
|
|
||||||
private @Nullable UserTypeResolver userTypeResolver;
|
private @Deprecated CodecRegistry codecRegistry = CodecRegistry.DEFAULT;
|
||||||
|
|
||||||
private CodecRegistry codecRegistry = CodecRegistry.DEFAULT;
|
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
private final Map<CqlIdentifier, Set<CassandraPersistentEntity<?>>> entitySetsByTableName = new HashMap<>();
|
private final Map<CqlIdentifier, Set<CassandraPersistentEntity<?>>> entitySetsByTableName = new HashMap<>();
|
||||||
@@ -105,7 +95,10 @@ public class CassandraMappingContext
|
|||||||
* @param userTypeResolver must not be {@literal null}.
|
* @param userTypeResolver must not be {@literal null}.
|
||||||
* @param tupleTypeFactory must not be {@literal null}.
|
* @param tupleTypeFactory must not be {@literal null}.
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
|
* @deprecated since 3.0, {@link UserTypeResolver} and {@link TupleTypeFactory} no longer required here as high-level
|
||||||
|
* type resolution went into {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public CassandraMappingContext(UserTypeResolver userTypeResolver, TupleTypeFactory tupleTypeFactory) {
|
public CassandraMappingContext(UserTypeResolver userTypeResolver, TupleTypeFactory tupleTypeFactory) {
|
||||||
|
|
||||||
setUserTypeResolver(userTypeResolver);
|
setUserTypeResolver(userTypeResolver);
|
||||||
@@ -192,7 +185,10 @@ public class CassandraMappingContext
|
|||||||
*
|
*
|
||||||
* @param customConversions must not be {@literal null}.
|
* @param customConversions must not be {@literal null}.
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
|
* @deprecated since 3.0. Use custom conversion through
|
||||||
|
* {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCustomConversions(CustomConversions customConversions) {
|
public void setCustomConversions(CustomConversions customConversions) {
|
||||||
|
|
||||||
Assert.notNull(customConversions, "CustomConversions must not be null");
|
Assert.notNull(customConversions, "CustomConversions must not be null");
|
||||||
@@ -200,6 +196,12 @@ public class CassandraMappingContext
|
|||||||
this.customConversions = customConversions;
|
this.customConversions = customConversions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* @deprecated since 3.0. Use custom conversion through
|
||||||
|
* {@link org.springframework.data.cassandra.core.convert.MappingCassandraConverter}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public CustomConversions getCustomConversions() {
|
public CustomConversions getCustomConversions() {
|
||||||
return customConversions;
|
return customConversions;
|
||||||
}
|
}
|
||||||
@@ -239,7 +241,10 @@ public class CassandraMappingContext
|
|||||||
*
|
*
|
||||||
* @param codecRegistry must not be {@literal null}.
|
* @param codecRegistry must not be {@literal null}.
|
||||||
* @since 2.2
|
* @since 2.2
|
||||||
|
* @deprecated since 3.0. Set {@link CodecRegistry} directly on
|
||||||
|
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCodecRegistry(CodecRegistry codecRegistry) {
|
public void setCodecRegistry(CodecRegistry codecRegistry) {
|
||||||
|
|
||||||
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
||||||
@@ -247,7 +252,12 @@ public class CassandraMappingContext
|
|||||||
this.codecRegistry = codecRegistry;
|
this.codecRegistry = codecRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
/**
|
||||||
|
* @return
|
||||||
|
* @deprecated since 3.0. Retrieve {@link CodecRegistry} directly from
|
||||||
|
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public CodecRegistry getCodecRegistry() {
|
public CodecRegistry getCodecRegistry() {
|
||||||
return this.codecRegistry;
|
return this.codecRegistry;
|
||||||
}
|
}
|
||||||
@@ -257,25 +267,21 @@ public class CassandraMappingContext
|
|||||||
*
|
*
|
||||||
* @param tupleTypeFactory must not be {@literal null}.
|
* @param tupleTypeFactory must not be {@literal null}.
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
|
* @deprecated since 3.0. Tuple type creation uses
|
||||||
|
* {@link com.datastax.oss.driver.api.core.type.DataTypes#tupleOf(DataType...)}
|
||||||
*/
|
*/
|
||||||
public void setTupleTypeFactory(TupleTypeFactory tupleTypeFactory) {
|
@Deprecated
|
||||||
|
public void setTupleTypeFactory(TupleTypeFactory tupleTypeFactory) {}
|
||||||
Assert.notNull(tupleTypeFactory, "TupleTypeFactory must not be null");
|
|
||||||
|
|
||||||
this.tupleTypeFactory = tupleTypeFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected TupleTypeFactory getTupleTypeFactory() {
|
|
||||||
return this.tupleTypeFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link UserTypeResolver}.
|
* Sets the {@link UserTypeResolver}.
|
||||||
*
|
*
|
||||||
* @param userTypeResolver must not be {@literal null}.
|
* @param userTypeResolver must not be {@literal null}.
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
|
* @deprecated since 3.0. Set {@link UserTypeResolver} directly on
|
||||||
|
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setUserTypeResolver(UserTypeResolver userTypeResolver) {
|
public void setUserTypeResolver(UserTypeResolver userTypeResolver) {
|
||||||
|
|
||||||
Assert.notNull(userTypeResolver, "UserTypeResolver must not be null");
|
Assert.notNull(userTypeResolver, "UserTypeResolver must not be null");
|
||||||
@@ -283,7 +289,13 @@ public class CassandraMappingContext
|
|||||||
this.userTypeResolver = userTypeResolver;
|
this.userTypeResolver = userTypeResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* @deprecated since 3.0. Retrieve {@link UserTypeResolver} directly from
|
||||||
|
* {@link org.springframework.data.cassandra.core.convert.CassandraConverter}.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@Deprecated
|
||||||
public UserTypeResolver getUserTypeResolver() {
|
public UserTypeResolver getUserTypeResolver() {
|
||||||
return this.userTypeResolver;
|
return this.userTypeResolver;
|
||||||
}
|
}
|
||||||
@@ -350,8 +362,8 @@ public class CassandraMappingContext
|
|||||||
protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
|
protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<T> entity = isUserDefinedType(typeInformation)
|
BasicCassandraPersistentEntity<T> entity = isUserDefinedType(typeInformation)
|
||||||
? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier(), resolveUserTypeResolver())
|
? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier())
|
||||||
: isTuple(typeInformation) ? new BasicCassandraPersistentTupleEntity<>(typeInformation, getTupleTypeFactory())
|
: isTuple(typeInformation) ? new BasicCassandraPersistentTupleEntity<>(typeInformation)
|
||||||
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
|
: new BasicCassandraPersistentEntity<>(typeInformation, getVerifier());
|
||||||
|
|
||||||
Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext);
|
Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext);
|
||||||
@@ -367,16 +379,6 @@ public class CassandraMappingContext
|
|||||||
return AnnotatedElementUtils.hasAnnotation(typeInformation.getType(), UserDefinedType.class);
|
return AnnotatedElementUtils.hasAnnotation(typeInformation.getType(), UserDefinedType.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private UserTypeResolver resolveUserTypeResolver() {
|
|
||||||
|
|
||||||
UserTypeResolver resolvedUserTypeResolver = getUserTypeResolver();
|
|
||||||
|
|
||||||
Assert.state(resolvedUserTypeResolver != null, "UserTypeResolver must not be null");
|
|
||||||
|
|
||||||
return resolvedUserTypeResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(org.springframework.data.mapping.model.Property, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
|
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(org.springframework.data.mapping.model.Property, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
|
||||||
*/
|
*/
|
||||||
@@ -385,8 +387,8 @@ public class CassandraMappingContext
|
|||||||
BasicCassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
BasicCassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||||
|
|
||||||
BasicCassandraPersistentProperty persistentProperty = owner.isTupleType()
|
BasicCassandraPersistentProperty persistentProperty = owner.isTupleType()
|
||||||
? new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder, getUserTypeResolver())
|
? new BasicCassandraPersistentTupleProperty(property, owner, simpleTypeHolder)
|
||||||
: new BasicCassandraPersistentProperty(property, owner, simpleTypeHolder, getUserTypeResolver());
|
: new BasicCassandraPersistentProperty(property, owner, simpleTypeHolder);
|
||||||
|
|
||||||
Optional.ofNullable(this.applicationContext).ifPresent(persistentProperty::setApplicationContext);
|
Optional.ofNullable(this.applicationContext).ifPresent(persistentProperty::setApplicationContext);
|
||||||
|
|
||||||
@@ -434,543 +436,4 @@ public class CassandraMappingContext
|
|||||||
.anyMatch(identifier::equals);
|
.anyMatch(identifier::equals);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link CreateTableSpecification} for the given entity, including all mapping information.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public CreateTableSpecification getCreateTableSpecificationFor(CassandraPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
|
||||||
|
|
||||||
return getCreateTableSpecificationFor(entity.getTableName(), entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link CreateTableSpecification} for the given entity using {@code tableName}, including all mapping
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* @param tableName must not be {@literal null}.
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @return
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public CreateTableSpecification getCreateTableSpecificationFor(
|
|
||||||
com.datastax.oss.driver.api.core.CqlIdentifier tableName, CassandraPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
Assert.notNull(tableName, "Table name must not be null");
|
|
||||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
|
||||||
|
|
||||||
CreateTableSpecification specification = createTable(tableName);
|
|
||||||
|
|
||||||
for (CassandraPersistentProperty property : entity) {
|
|
||||||
|
|
||||||
if (property.isCompositePrimaryKey()) {
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> primaryKeyEntity = getRequiredPersistentEntity(property.getRawType());
|
|
||||||
|
|
||||||
for (CassandraPersistentProperty primaryKeyProperty : primaryKeyEntity) {
|
|
||||||
|
|
||||||
DataType dataType = getDataTypeWithUserTypeFactory(primaryKeyProperty, DataTypeProvider.ShallowType);
|
|
||||||
|
|
||||||
if (primaryKeyProperty.isPartitionKeyColumn()) {
|
|
||||||
specification.partitionKeyColumn(primaryKeyProperty.getRequiredColumnName(), dataType);
|
|
||||||
} else { // cluster column
|
|
||||||
specification.clusteredKeyColumn(primaryKeyProperty.getRequiredColumnName(), dataType,
|
|
||||||
primaryKeyProperty.getPrimaryKeyOrdering());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DataType type = UserTypeUtil
|
|
||||||
.potentiallyFreeze(getDataTypeWithUserTypeFactory(property, DataTypeProvider.ShallowType));
|
|
||||||
|
|
||||||
if (property.isIdProperty() || property.isPartitionKeyColumn()) {
|
|
||||||
specification.partitionKeyColumn(property.getRequiredColumnName(), type);
|
|
||||||
} else if (property.isClusterKeyColumn()) {
|
|
||||||
specification.clusteredKeyColumn(property.getRequiredColumnName(), type, property.getPrimaryKeyOrdering());
|
|
||||||
} else {
|
|
||||||
specification.column(property.getRequiredColumnName(), type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (specification.getPartitionKeyColumns().isEmpty()) {
|
|
||||||
throw new MappingException(String.format("No partition key columns found in entity [%s]", entity.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return specification;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @return
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
public List<CreateIndexSpecification> getCreateIndexSpecificationsFor(CassandraPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
|
||||||
|
|
||||||
List<CreateIndexSpecification> indexes = new ArrayList<>();
|
|
||||||
|
|
||||||
for (CassandraPersistentProperty property : entity) {
|
|
||||||
if (property.isCompositePrimaryKey()) {
|
|
||||||
indexes.addAll(getCreateIndexSpecificationsFor(getRequiredPersistentEntity(property)));
|
|
||||||
} else {
|
|
||||||
indexes.addAll(IndexSpecificationFactory.createIndexSpecifications(property));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
indexes.forEach(it -> it.tableName(entity.getTableName()));
|
|
||||||
|
|
||||||
return indexes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link CreateUserTypeSpecification} for the given entity, including all mapping information.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public CreateUserTypeSpecification getCreateUserTypeSpecificationFor(CassandraPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
|
||||||
|
|
||||||
CreateUserTypeSpecification specification = CreateUserTypeSpecification.createType(entity.getTableName());
|
|
||||||
|
|
||||||
for (CassandraPersistentProperty property : entity) {
|
|
||||||
// Use frozen literal to not resolve types from Cassandra; At this stage, they might be not created yet.
|
|
||||||
specification.field(property.getRequiredColumnName(),
|
|
||||||
getDataTypeWithUserTypeFactory(property, DataTypeProvider.FrozenLiteral));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (specification.getFields().isEmpty()) {
|
|
||||||
throw new MappingException(String.format("No fields in user type [%s]", entity.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return specification;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the data type based on the given {@code type}. Cassandra {@link DataType types} are determined using
|
|
||||||
* simple types and configured {@link org.springframework.data.convert.CustomConversions}.
|
|
||||||
*
|
|
||||||
* @param type must not be {@literal null}.
|
|
||||||
* @return the Cassandra {@link DataType type}.
|
|
||||||
* @see org.springframework.data.convert.CustomConversions
|
|
||||||
* @see CassandraSimpleTypeHolder
|
|
||||||
* @since 1.5
|
|
||||||
*/
|
|
||||||
public DataType getDataType(Class<?> type) {
|
|
||||||
return CassandraSimpleTypeHolder.getDataTypeFor(this.customConversions.getCustomWriteTarget(type).orElse(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
public TupleType getTupleType(CassandraPersistentEntity<?> persistentEntity) {
|
|
||||||
|
|
||||||
Assert.notNull(persistentEntity, "CassandraPersistentEntity must not be null");
|
|
||||||
Assert.isTrue(persistentEntity.isTupleType(), "CassandraPersistentEntity is not a mapped tuple type");
|
|
||||||
|
|
||||||
return getTupleType(DataTypeProvider.EntityUserType, persistentEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the data type of the property. Cassandra {@link DataType types} are determined using simple types and
|
|
||||||
* configured {@link org.springframework.data.convert.CustomConversions}.
|
|
||||||
*
|
|
||||||
* @param property must not be {@literal null}.
|
|
||||||
* @return the Cassandra {@link DataType type}.
|
|
||||||
* @see org.springframework.data.convert.CustomConversions
|
|
||||||
* @see CassandraSimpleTypeHolder
|
|
||||||
* @since 1.5
|
|
||||||
*/
|
|
||||||
public DataType getDataType(CassandraPersistentProperty property) {
|
|
||||||
return getDataTypeWithUserTypeFactory(property, DataTypeProvider.EntityUserType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType getDataTypeWithUserTypeFactory(CassandraPersistentProperty property,
|
|
||||||
DataTypeProvider dataTypeProvider) {
|
|
||||||
|
|
||||||
if (property.isAnnotationPresent(CassandraType.class)) {
|
|
||||||
|
|
||||||
CassandraType annotation = property.getRequiredAnnotation(CassandraType.class);
|
|
||||||
|
|
||||||
if (annotation.type() == Name.TUPLE) {
|
|
||||||
|
|
||||||
DataType[] dataTypes = Arrays.stream(annotation.typeArguments()).map(CassandraSimpleTypeHolder::getDataTypeFor)
|
|
||||||
.toArray(DataType[]::new);
|
|
||||||
|
|
||||||
return getTupleTypeFactory().create(dataTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (annotation.type() == Name.UDT) {
|
|
||||||
|
|
||||||
com.datastax.oss.driver.api.core.CqlIdentifier userTypeName = com.datastax.oss.driver.api.core.CqlIdentifier
|
|
||||||
.fromCql(annotation.userTypeName());
|
|
||||||
|
|
||||||
DataType userType = dataTypeProvider.getUserType(userTypeName, resolveUserTypeResolver());
|
|
||||||
|
|
||||||
if (userType == null) {
|
|
||||||
throw new MappingException(String.format("User type [%s] not found", userTypeName));
|
|
||||||
}
|
|
||||||
|
|
||||||
DataType dataType = getUserDataType(property.getTypeInformation(), userType);
|
|
||||||
|
|
||||||
if (dataType != null) {
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return property.getDataType();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TupleValue.class.isAssignableFrom(property.getType())) {
|
|
||||||
throw new MappingException(String.format(
|
|
||||||
"Unsupported raw TupleType to DataType for property [%s] in entity [%s]; Consider adding @CassandraType.",
|
|
||||||
property.getName(), property.getOwner().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UdtValue.class.isAssignableFrom(property.getType())) {
|
|
||||||
throw new MappingException(String.format(
|
|
||||||
"Unsupported raw UdtValue to DataType for property [%s] in entity [%s]; Consider adding @CassandraType.",
|
|
||||||
property.getName(), property.getOwner().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
DataType dataType = getDataTypeWithUserTypeFactory(property.getTypeInformation(), dataTypeProvider,
|
|
||||||
property::getDataType);
|
|
||||||
|
|
||||||
if (dataType == null) {
|
|
||||||
throw new MappingException(
|
|
||||||
String.format("Cannot resolve DataType for property [%s] in entity [%s]; Consider adding @CassandraType.",
|
|
||||||
property.getName(), property.getOwner().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataType;
|
|
||||||
} catch (InvalidDataAccessApiUsageException e) {
|
|
||||||
throw new MappingException(String.format("%s. Consider adding @CassandraType.", e.getMessage()), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DataType getDataTypeWithUserTypeFactory(TypeInformation<?> typeInformation, DataTypeProvider dataTypeProvider,
|
|
||||||
Supplier<DataType> fallback) {
|
|
||||||
|
|
||||||
Optional<DataType> customWriteTarget = this.customConversions.getCustomWriteTarget(typeInformation.getType())
|
|
||||||
.map(it -> {
|
|
||||||
typeInformation.getType();
|
|
||||||
return CassandraSimpleTypeHolder.getDataTypeFor(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
DataType dataType = customWriteTarget.orElseGet(() -> {
|
|
||||||
|
|
||||||
Class<?> propertyType = typeInformation.getRequiredActualType().getType();
|
|
||||||
|
|
||||||
return this.customConversions.getCustomWriteTarget(propertyType).filter(it -> !typeInformation.isMap())
|
|
||||||
.map(it -> {
|
|
||||||
|
|
||||||
if (typeInformation.isCollectionLike()) {
|
|
||||||
if (List.class.isAssignableFrom(typeInformation.getType())) {
|
|
||||||
return DataTypes.listOf(CassandraSimpleTypeHolder.getDataTypeFor(it));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Set.class.isAssignableFrom(typeInformation.getType())) {
|
|
||||||
return DataTypes.setOf(CassandraSimpleTypeHolder.getDataTypeFor(it));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CassandraSimpleTypeHolder.getDataTypeFor(it);
|
|
||||||
|
|
||||||
}).orElse(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dataType != null) {
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeInformation.isCollectionLike()) {
|
|
||||||
|
|
||||||
TypeInformation<?> componentType = typeInformation.getRequiredActualType();
|
|
||||||
BasicCassandraPersistentEntity<?> persistentEntity = getPersistentEntity(componentType);
|
|
||||||
TypeInformation<?> typeToUse = persistentEntity != null ? persistentEntity.getTypeInformation() : componentType;
|
|
||||||
|
|
||||||
if (List.class.isAssignableFrom(typeInformation.getType())) {
|
|
||||||
return DataTypes.listOf(getDataTypeWithUserTypeFactory(typeToUse, dataTypeProvider, fallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Set.class.isAssignableFrom(typeInformation.getType())) {
|
|
||||||
return DataTypes.setOf(getDataTypeWithUserTypeFactory(typeToUse, dataTypeProvider, fallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Unsupported collection type: " + typeInformation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeInformation.isMap()) {
|
|
||||||
return getMapDataType(typeInformation, dataTypeProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<?> persistentEntity = getPersistentEntity(typeInformation);
|
|
||||||
|
|
||||||
if (persistentEntity != null) {
|
|
||||||
|
|
||||||
if (persistentEntity.isUserDefinedType()) {
|
|
||||||
|
|
||||||
DataType udtType = dataTypeProvider.getDataType(persistentEntity);
|
|
||||||
|
|
||||||
if (udtType != null) {
|
|
||||||
return udtType;
|
|
||||||
}
|
|
||||||
} else if (persistentEntity.isTupleType()) {
|
|
||||||
return getTupleType(dataTypeProvider, persistentEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataTypeProvider.getDataType(persistentEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
DataType determinedType = CassandraSimpleTypeHolder.getDataTypeFor(typeInformation.getType());
|
|
||||||
|
|
||||||
if (determinedType != null) {
|
|
||||||
return determinedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fallback.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private TupleType getTupleType(DataTypeProvider dataTypeProvider, CassandraPersistentEntity<?> persistentEntity) {
|
|
||||||
|
|
||||||
List<DataType> types = new ArrayList<>();
|
|
||||||
|
|
||||||
for (CassandraPersistentProperty persistentProperty : persistentEntity) {
|
|
||||||
types.add(getDataTypeWithUserTypeFactory(persistentProperty, dataTypeProvider));
|
|
||||||
}
|
|
||||||
|
|
||||||
return getTupleTypeFactory().create(types);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
private DataType getMapDataType(TypeInformation<?> typeInformation, DataTypeProvider dataTypeProvider) {
|
|
||||||
|
|
||||||
TypeInformation<?> keyTypeInformation = typeInformation.getComponentType();
|
|
||||||
TypeInformation<?> valueTypeInformation = typeInformation.getMapValueType();
|
|
||||||
|
|
||||||
DataType keyType = getDataTypeWithUserTypeFactory(keyTypeInformation, dataTypeProvider, () -> {
|
|
||||||
|
|
||||||
DataType type = CassandraSimpleTypeHolder.getDataTypeFor(keyTypeInformation.getType());
|
|
||||||
|
|
||||||
if (type != null) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new MappingException(String.format("Cannot resolve key type for [%s]", typeInformation));
|
|
||||||
});
|
|
||||||
|
|
||||||
DataType valueType = getDataTypeWithUserTypeFactory(valueTypeInformation, dataTypeProvider, () -> {
|
|
||||||
|
|
||||||
DataType type = CassandraSimpleTypeHolder.getDataTypeFor(valueTypeInformation.getType());
|
|
||||||
|
|
||||||
if (type != null) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new MappingException("Cannot resolve value type for " + typeInformation + ".");
|
|
||||||
});
|
|
||||||
|
|
||||||
return DataTypes.mapOf(keyType, valueType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DataType getUserDataType(TypeInformation<?> property, @Nullable DataType elementType) {
|
|
||||||
|
|
||||||
if (property.isCollectionLike()) {
|
|
||||||
|
|
||||||
if (List.class.isAssignableFrom(property.getType())) {
|
|
||||||
return DataTypes.listOf(elementType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Set.class.isAssignableFrom(property.getType())) {
|
|
||||||
return DataTypes.setOf(elementType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !(property.isCollectionLike() || property.isMap()) ? elementType : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Jens Schauder
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 1.5.1
|
|
||||||
*/
|
|
||||||
enum DataTypeProvider {
|
|
||||||
|
|
||||||
EntityUserType {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType getDataType(CassandraPersistentEntity<?> entity) {
|
|
||||||
return entity.isTupleType() ? entity.getTupleType() : entity.getUserType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
DataType getUserType(com.datastax.oss.driver.api.core.CqlIdentifier userTypeName,
|
|
||||||
UserTypeResolver userTypeResolver) {
|
|
||||||
return userTypeResolver.resolveType(userTypeName);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ShallowType {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType getDataType(CassandraPersistentEntity<?> entity) {
|
|
||||||
return entity.isTupleType() ? entity.getTupleType() : new ShallowUserDefinedType(entity.getTableName(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
DataType getUserType(com.datastax.oss.driver.api.core.CqlIdentifier userTypeName,
|
|
||||||
UserTypeResolver userTypeResolver) {
|
|
||||||
return new ShallowUserDefinedType(userTypeName, false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
FrozenLiteral {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType getDataType(CassandraPersistentEntity<?> entity) {
|
|
||||||
return new ShallowUserDefinedType(entity.getTableName(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
DataType getUserType(com.datastax.oss.driver.api.core.CqlIdentifier userTypeName,
|
|
||||||
UserTypeResolver userTypeResolver) {
|
|
||||||
return new ShallowUserDefinedType(userTypeName, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the data type for the {@link CassandraPersistentEntity}.
|
|
||||||
*
|
|
||||||
* @param entity must not be {@literal null}.
|
|
||||||
* @return the {@link DataType}.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
abstract DataType getDataType(CassandraPersistentEntity<?> entity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the user-defined type {@code userTypeName}.
|
|
||||||
*
|
|
||||||
* @param userTypeName must not be {@literal null}.
|
|
||||||
* @param userTypeResolver must not be {@literal null}.
|
|
||||||
* @return the {@link DataType}.
|
|
||||||
* @since 2.0.1
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
abstract DataType getUserType(com.datastax.oss.driver.api.core.CqlIdentifier userTypeName,
|
|
||||||
UserTypeResolver userTypeResolver);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ShallowUserDefinedType implements com.datastax.oss.driver.api.core.type.UserDefinedType {
|
|
||||||
|
|
||||||
private final CqlIdentifier name;
|
|
||||||
private final boolean frozen;
|
|
||||||
|
|
||||||
public ShallowUserDefinedType(String name, boolean frozen) {
|
|
||||||
this(CqlIdentifier.fromInternal(name), frozen);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShallowUserDefinedType(CqlIdentifier name, boolean frozen) {
|
|
||||||
this.name = name;
|
|
||||||
this.frozen = frozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CqlIdentifier getKeyspace() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CqlIdentifier getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFrozen() {
|
|
||||||
return frozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CqlIdentifier> getFieldNames() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int firstIndexOf(CqlIdentifier id) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int firstIndexOf(String name) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DataType> getFieldTypes() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public com.datastax.oss.driver.api.core.type.UserDefinedType copy(boolean newFrozen) {
|
|
||||||
return new ShallowUserDefinedType(this.name, newFrozen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UdtValue newValue() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UdtValue newValue(@edu.umd.cs.findbugs.annotations.NonNull Object... fields) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AttachmentPoint getAttachmentPoint() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDetached() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attach(@edu.umd.cs.findbugs.annotations.NonNull AttachmentPoint attachmentPoint) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"This implementation should only be used internally, this is likely a driver bug");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
if (!(o instanceof com.datastax.oss.driver.api.core.type.UserDefinedType))
|
|
||||||
return false;
|
|
||||||
com.datastax.oss.driver.api.core.type.UserDefinedType that = (com.datastax.oss.driver.api.core.type.UserDefinedType) o;
|
|
||||||
return isFrozen() == that.isFrozen() && Objects.equals(getName(), that.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(name, frozen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ShallowUserDefinedType{" + "name=" + name + ", frozen=" + frozen + '}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,9 @@
|
|||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
import org.springframework.data.mapping.PersistentEntity;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cassandra specific {@link PersistentEntity} abstraction.
|
* Cassandra specific {@link PersistentEntity} abstraction.
|
||||||
@@ -79,14 +77,6 @@ public interface CassandraPersistentEntity<T> extends PersistentEntity<T, Cassan
|
|||||||
*/
|
*/
|
||||||
boolean isTupleType();
|
boolean isTupleType();
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the {@link TupleType} matching the data types from {@link BasicCassandraPersistentTupleProperty mapped
|
|
||||||
* tuple elements}.
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
TupleType getTupleType();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@literal true} if the type is a mapped user defined type.
|
* @return {@literal true} if the type is a mapped user defined type.
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
@@ -94,12 +84,4 @@ public interface CassandraPersistentEntity<T> extends PersistentEntity<T, Cassan
|
|||||||
*/
|
*/
|
||||||
boolean isUserDefinedType();
|
boolean isUserDefinedType();
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the CQL {@link UserType} if the type is a mapped user defined type, otherwise {@literal null}.
|
|
||||||
* @since 1.5
|
|
||||||
* @see UserDefinedType
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
com.datastax.oss.driver.api.core.type.UserDefinedType getUserType();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ import java.lang.annotation.Annotation;
|
|||||||
import java.lang.reflect.AnnotatedType;
|
import java.lang.reflect.AnnotatedType;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
|
||||||
import org.springframework.data.cassandra.core.cql.Ordering;
|
import org.springframework.data.cassandra.core.cql.Ordering;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cassandra specific {@link org.springframework.data.mapping.PersistentProperty} extension.
|
* Cassandra specific {@link org.springframework.data.mapping.PersistentProperty} extension.
|
||||||
@@ -88,15 +86,6 @@ public interface CassandraPersistentProperty
|
|||||||
return columnName;
|
return columnName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The column's data type. Not valid for a composite primary key.
|
|
||||||
*
|
|
||||||
* @return the Cassandra {@link DataType}
|
|
||||||
* @throws InvalidDataAccessApiUsageException if the {@link DataType} cannot be resolved
|
|
||||||
* @see CassandraType
|
|
||||||
*/
|
|
||||||
DataType getDataType();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to force-quote the column names of this property.
|
* Whether to force-quote the column names of this property.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import org.springframework.data.mapping.MappingException;
|
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
|
|
||||||
@@ -32,27 +29,16 @@ import com.datastax.oss.driver.api.core.CqlIdentifier;
|
|||||||
*/
|
*/
|
||||||
public class CassandraUserTypePersistentEntity<T> extends BasicCassandraPersistentEntity<T> {
|
public class CassandraUserTypePersistentEntity<T> extends BasicCassandraPersistentEntity<T> {
|
||||||
|
|
||||||
private final UserTypeResolver resolver;
|
|
||||||
|
|
||||||
private final Object lock = new Object();
|
|
||||||
|
|
||||||
private volatile @Nullable com.datastax.oss.driver.api.core.type.UserDefinedType userType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link CassandraUserTypePersistentEntity}.
|
* Create a new {@link CassandraUserTypePersistentEntity}.
|
||||||
*
|
*
|
||||||
* @param typeInformation must not be {@literal null}.
|
* @param typeInformation must not be {@literal null}.
|
||||||
* @param verifier must not be {@literal null}.
|
* @param verifier must not be {@literal null}.
|
||||||
* @param resolver must not be {@literal null}.
|
|
||||||
*/
|
*/
|
||||||
public CassandraUserTypePersistentEntity(TypeInformation<T> typeInformation,
|
public CassandraUserTypePersistentEntity(TypeInformation<T> typeInformation,
|
||||||
CassandraPersistentEntityMetadataVerifier verifier, UserTypeResolver resolver) {
|
CassandraPersistentEntityMetadataVerifier verifier) {
|
||||||
|
|
||||||
super(typeInformation, verifier);
|
super(typeInformation, verifier);
|
||||||
|
|
||||||
Assert.notNull(resolver, "UserTypeResolver must not be null");
|
|
||||||
|
|
||||||
this.resolver = resolver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -77,29 +63,4 @@ public class CassandraUserTypePersistentEntity<T> extends BasicCassandraPersiste
|
|||||||
public boolean isUserDefinedType() {
|
public boolean isUserDefinedType() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity#getUserType()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public com.datastax.oss.driver.api.core.type.UserDefinedType getUserType() {
|
|
||||||
|
|
||||||
if (userType == null) {
|
|
||||||
synchronized (lock) {
|
|
||||||
if (userType == null) {
|
|
||||||
|
|
||||||
CqlIdentifier identifier = determineTableName();
|
|
||||||
com.datastax.oss.driver.api.core.type.UserDefinedType userType = resolver.resolveType(identifier);
|
|
||||||
|
|
||||||
if (userType == null) {
|
|
||||||
throw new MappingException(String.format("User type [%s] not found", identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userType = userType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return userType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.datastax.oss.driver.internal.core.type.DefaultTupleType;
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public enum SimpleTupleTypeFactory implements TupleTypeFactory {
|
public enum SimpleTupleTypeFactory implements TupleTypeFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ import com.datastax.oss.driver.api.core.type.TupleType;
|
|||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @see SimpleTupleTypeFactory
|
* @see SimpleTupleTypeFactory
|
||||||
* @see CodecRegistryTupleTypeFactory
|
* @see CodecRegistryTupleTypeFactory
|
||||||
|
* @deprecated since 3.0
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
@Deprecated
|
||||||
public interface TupleTypeFactory {
|
public interface TupleTypeFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import org.springframework.util.Assert;
|
|||||||
|
|
||||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for {@link RepositoryQuery} implementations for Cassandra.
|
* Base class for {@link RepositoryQuery} implementations for Cassandra.
|
||||||
@@ -48,7 +47,6 @@ public abstract class AbstractCassandraQuery extends CassandraRepositoryQuerySup
|
|||||||
|
|
||||||
private final CassandraOperations operations;
|
private final CassandraOperations operations;
|
||||||
|
|
||||||
private final CodecRegistry codecRegistry;
|
|
||||||
|
|
||||||
private static CassandraConverter toConverter(CassandraOperations operations) {
|
private static CassandraConverter toConverter(CassandraOperations operations) {
|
||||||
|
|
||||||
@@ -73,7 +71,6 @@ public abstract class AbstractCassandraQuery extends CassandraRepositoryQuerySup
|
|||||||
super(queryMethod, toMappingContext(operations));
|
super(queryMethod, toMappingContext(operations));
|
||||||
|
|
||||||
this.operations = operations;
|
this.operations = operations;
|
||||||
this.codecRegistry = operations.getConverter().getMappingContext().getCodecRegistry();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,7 +91,7 @@ public abstract class AbstractCassandraQuery extends CassandraRepositoryQuerySup
|
|||||||
public Object execute(Object[] parameters) {
|
public Object execute(Object[] parameters) {
|
||||||
|
|
||||||
CassandraParameterAccessor parameterAccessor = new ConvertingParameterAccessor(toConverter(getOperations()),
|
CassandraParameterAccessor parameterAccessor = new ConvertingParameterAccessor(toConverter(getOperations()),
|
||||||
new CassandraParametersParameterAccessor(getQueryMethod(), parameters), codecRegistry);
|
new CassandraParametersParameterAccessor(getQueryMethod(), parameters));
|
||||||
|
|
||||||
ResultProcessor resultProcessor = getQueryMethod().getResultProcessor().withDynamicProjection(parameterAccessor);
|
ResultProcessor resultProcessor = getQueryMethod().getResultProcessor().withDynamicProjection(parameterAccessor);
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import org.springframework.util.Assert;
|
|||||||
|
|
||||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for reactive {@link RepositoryQuery} implementations for Cassandra.
|
* Base class for reactive {@link RepositoryQuery} implementations for Cassandra.
|
||||||
@@ -53,8 +52,6 @@ public abstract class AbstractReactiveCassandraQuery extends CassandraRepository
|
|||||||
|
|
||||||
private final ReactiveCassandraOperations operations;
|
private final ReactiveCassandraOperations operations;
|
||||||
|
|
||||||
private final CodecRegistry codecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link AbstractReactiveCassandraQuery} from the given {@link CassandraQueryMethod} and
|
* Create a new {@link AbstractReactiveCassandraQuery} from the given {@link CassandraQueryMethod} and
|
||||||
* {@link CassandraOperations}.
|
* {@link CassandraOperations}.
|
||||||
@@ -67,7 +64,6 @@ public abstract class AbstractReactiveCassandraQuery extends CassandraRepository
|
|||||||
super(method, getRequiredMappingContext(operations));
|
super(method, getRequiredMappingContext(operations));
|
||||||
|
|
||||||
this.operations = operations;
|
this.operations = operations;
|
||||||
this.codecRegistry = operations.getConverter().getMappingContext().getCodecRegistry();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -102,7 +98,7 @@ public abstract class AbstractReactiveCassandraQuery extends CassandraRepository
|
|||||||
parameters);
|
parameters);
|
||||||
|
|
||||||
CassandraParameterAccessor convertingParameterAccessor = new ConvertingParameterAccessor(
|
CassandraParameterAccessor convertingParameterAccessor = new ConvertingParameterAccessor(
|
||||||
getRequiredConverter(getReactiveCassandraOperations()), parameterAccessor, codecRegistry);
|
getRequiredConverter(getReactiveCassandraOperations()), parameterAccessor);
|
||||||
|
|
||||||
Statement<?> statement = createQuery(convertingParameterAccessor);
|
Statement<?> statement = createQuery(convertingParameterAccessor);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package org.springframework.data.cassandra.repository.query;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||||
import org.springframework.data.cassandra.core.cql.QueryOptions;
|
import org.springframework.data.cassandra.core.cql.QueryOptions;
|
||||||
@@ -26,12 +25,9 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentProper
|
|||||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
|
||||||
import org.springframework.data.util.TypeInformation;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
import com.datastax.oss.driver.api.core.type.DataType;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom {@link org.springframework.data.repository.query.ParameterAccessor} that uses a {@link CassandraConverter} to
|
* Custom {@link org.springframework.data.repository.query.ParameterAccessor} that uses a {@link CassandraConverter} to
|
||||||
@@ -43,14 +39,11 @@ import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|||||||
*/
|
*/
|
||||||
class ConvertingParameterAccessor implements CassandraParameterAccessor {
|
class ConvertingParameterAccessor implements CassandraParameterAccessor {
|
||||||
|
|
||||||
private static final TypeInformation<Set> SET = ClassTypeInformation.from(Set.class);
|
|
||||||
|
|
||||||
private final CassandraConverter converter;
|
private final CassandraConverter converter;
|
||||||
|
|
||||||
private final CassandraParameterAccessor delegate;
|
private final CassandraParameterAccessor delegate;
|
||||||
|
|
||||||
ConvertingParameterAccessor(CassandraConverter converter, CassandraParameterAccessor delegate,
|
ConvertingParameterAccessor(CassandraConverter converter, CassandraParameterAccessor delegate) {
|
||||||
CodecRegistry codecRegistry) {
|
|
||||||
|
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
|||||||
@@ -33,14 +33,17 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import org.springframework.data.cassandra.core.convert.SchemaFactory;
|
||||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.UserTypeNameSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.UserTypeNameSpecification;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||||
import org.springframework.data.cassandra.core.mapping.UserDefinedType;
|
import org.springframework.data.cassandra.core.mapping.UserDefinedType;
|
||||||
|
import org.springframework.data.convert.CustomConversions;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
|
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link CassandraPersistentEntitySchemaCreator}.
|
* Unit tests for {@link CassandraPersistentEntitySchemaCreator}.
|
||||||
@@ -66,6 +69,9 @@ public class CassandraPersistentEntitySchemaCreatorUnitTests extends CassandraPe
|
|||||||
});
|
});
|
||||||
|
|
||||||
when(adminOperations.getCqlOperations()).thenReturn(operations);
|
when(adminOperations.getCqlOperations()).thenReturn(operations);
|
||||||
|
when(adminOperations.getSchemaFactory()).thenReturn(new SchemaFactory(context,
|
||||||
|
new CustomConversions(CustomConversions.StoreConversions.NONE, Collections.emptyList()),
|
||||||
|
CodecRegistry.DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-687
|
@Test // DATACASS-687
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import org.junit.Test;
|
|||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||||
import org.springframework.data.cassandra.core.CassandraTemplate;
|
import org.springframework.data.cassandra.core.CassandraTemplate;
|
||||||
import org.springframework.data.cassandra.core.mapping.SimpleTupleTypeFactory;
|
|
||||||
import org.springframework.data.cassandra.domain.AllPossibleTypes;
|
import org.springframework.data.cassandra.domain.AllPossibleTypes;
|
||||||
import org.springframework.data.cassandra.repository.support.SchemaTestUtils;
|
import org.springframework.data.cassandra.repository.support.SchemaTestUtils;
|
||||||
import org.springframework.data.cassandra.support.CassandraVersion;
|
import org.springframework.data.cassandra.support.CassandraVersion;
|
||||||
@@ -470,7 +469,7 @@ public class CassandraTypeMappingIntegrationTests extends AbstractKeyspaceCreati
|
|||||||
@Test // DATACASS-284
|
@Test // DATACASS-284
|
||||||
public void shouldReadAndWriteTupleType() {
|
public void shouldReadAndWriteTupleType() {
|
||||||
|
|
||||||
TupleType tupleType = SimpleTupleTypeFactory.DEFAULT.create(DataTypes.TEXT, DataTypes.BIGINT);
|
TupleType tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.BIGINT);
|
||||||
|
|
||||||
AllPossibleTypes entity = new AllPossibleTypes("1");
|
AllPossibleTypes entity = new AllPossibleTypes("1");
|
||||||
|
|
||||||
@@ -487,7 +486,7 @@ public class CassandraTypeMappingIntegrationTests extends AbstractKeyspaceCreati
|
|||||||
@Test // DATACASS-284
|
@Test // DATACASS-284
|
||||||
public void shouldReadAndWriteListOfTuples() {
|
public void shouldReadAndWriteListOfTuples() {
|
||||||
|
|
||||||
TupleType tupleType = SimpleTupleTypeFactory.DEFAULT.create(DataTypes.TEXT, DataTypes.BIGINT);
|
TupleType tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.BIGINT);
|
||||||
|
|
||||||
ListOfTuples entity = new ListOfTuples();
|
ListOfTuples entity = new ListOfTuples();
|
||||||
|
|
||||||
|
|||||||
@@ -21,16 +21,20 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
|
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||||
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
import com.datastax.oss.driver.api.core.type.DataTypes;
|
||||||
|
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link DefaultColumnTypeResolver}.
|
* Unit tests for {@link DefaultColumnTypeResolver}.
|
||||||
@@ -40,7 +44,8 @@ import com.datastax.oss.driver.api.core.type.DataTypes;
|
|||||||
public class ColumnTypeResolverUnitTests {
|
public class ColumnTypeResolverUnitTests {
|
||||||
|
|
||||||
CassandraMappingContext mappingContext = new CassandraMappingContext();
|
CassandraMappingContext mappingContext = new CassandraMappingContext();
|
||||||
ColumnTypeResolver resolver = new DefaultColumnTypeResolver(mappingContext);
|
ColumnTypeResolver resolver = new DefaultColumnTypeResolver(mappingContext, null, () -> CodecRegistry.DEFAULT,
|
||||||
|
mappingContext::getCustomConversions);
|
||||||
|
|
||||||
@Test // DATACASS-743
|
@Test // DATACASS-743
|
||||||
public void shouldResolveSimpleType() {
|
public void shouldResolveSimpleType() {
|
||||||
@@ -177,10 +182,23 @@ public class ColumnTypeResolverUnitTests {
|
|||||||
|
|
||||||
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(Person.class);
|
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(Person.class);
|
||||||
|
|
||||||
assertThat(resolver.resolve(entity.getRequiredPersistentProperty("tupleValue")).getType())
|
CassandraColumnType columnType = resolver.resolve(entity.getRequiredPersistentProperty("tupleValue"));
|
||||||
|
assertThat(columnType.getType())
|
||||||
.isEqualTo(TupleValue.class);
|
.isEqualTo(TupleValue.class);
|
||||||
assertThat(resolver.resolve(entity.getRequiredPersistentProperty("tupleValue")).getDataType())
|
|
||||||
.isEqualTo(DataTypes.tupleOf());
|
assertThatThrownBy(columnType::getDataType).isInstanceOf(MappingException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-375, DATACASS-743
|
||||||
|
public void UuidshouldMapToUUIDByDefault() {
|
||||||
|
|
||||||
|
CassandraPersistentProperty uuidProperty = mappingContext.getRequiredPersistentEntity(TypeWithUUIDColumn.class)
|
||||||
|
.getRequiredPersistentProperty("uuid");
|
||||||
|
CassandraPersistentProperty timeUUIDProperty = mappingContext.getRequiredPersistentEntity(TypeWithUUIDColumn.class)
|
||||||
|
.getRequiredPersistentProperty("timeUUID");
|
||||||
|
|
||||||
|
assertThat(resolver.resolve(uuidProperty).getDataType()).isEqualTo(DataTypes.UUID);
|
||||||
|
assertThat(resolver.resolve(timeUUIDProperty).getDataType()).isEqualTo(DataTypes.TIMEUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Person {
|
static class Person {
|
||||||
@@ -213,6 +231,13 @@ public class ColumnTypeResolverUnitTests {
|
|||||||
TupleValue tupleValue;
|
TupleValue tupleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TypeWithUUIDColumn {
|
||||||
|
|
||||||
|
UUID uuid;
|
||||||
|
|
||||||
|
@CassandraType(type = CassandraType.Name.TIMEUUID) UUID timeUUID;
|
||||||
|
}
|
||||||
|
|
||||||
enum MyEnum {
|
enum MyEnum {
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
import static org.junit.Assume.*;
|
import static org.junit.Assume.*;
|
||||||
@@ -29,6 +29,10 @@ import org.springframework.data.cassandra.core.cql.generator.CreateIndexCqlGener
|
|||||||
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.BasicCassandraPersistentEntity;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Indexed;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.SASI;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.StandardAnalyzed;
|
import org.springframework.data.cassandra.core.mapping.SASI.StandardAnalyzed;
|
||||||
import org.springframework.data.cassandra.support.CassandraVersion;
|
import org.springframework.data.cassandra.support.CassandraVersion;
|
||||||
import org.springframework.data.cassandra.test.util.AbstractKeyspaceCreatingIntegrationTest;
|
import org.springframework.data.cassandra.test.util.AbstractKeyspaceCreatingIntegrationTest;
|
||||||
@@ -46,6 +50,7 @@ import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
|
|||||||
public class IndexCreationIntegrationTests extends AbstractKeyspaceCreatingIntegrationTest {
|
public class IndexCreationIntegrationTests extends AbstractKeyspaceCreatingIntegrationTest {
|
||||||
|
|
||||||
private CassandraMappingContext mappingContext = new CassandraMappingContext();
|
private CassandraMappingContext mappingContext = new CassandraMappingContext();
|
||||||
|
private SchemaFactory schemaFactory = new SchemaFactory(new MappingCassandraConverter(mappingContext));
|
||||||
private Version cassandraVersion;
|
private Version cassandraVersion;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -60,8 +65,8 @@ public class IndexCreationIntegrationTests extends AbstractKeyspaceCreatingInteg
|
|||||||
public void shouldCreateSecondaryIndex() throws InterruptedException {
|
public void shouldCreateSecondaryIndex() throws InterruptedException {
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(WithSecondaryIndex.class);
|
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(WithSecondaryIndex.class);
|
||||||
CreateTableSpecification createTable = mappingContext.getCreateTableSpecificationFor(entity);
|
CreateTableSpecification createTable = schemaFactory.getCreateTableSpecificationFor(entity);
|
||||||
List<CreateIndexSpecification> createIndexes = mappingContext.getCreateIndexSpecificationsFor(entity);
|
List<CreateIndexSpecification> createIndexes = schemaFactory.getCreateIndexSpecificationsFor(entity);
|
||||||
|
|
||||||
session.execute(CreateTableCqlGenerator.toCql(createTable));
|
session.execute(CreateTableCqlGenerator.toCql(createTable));
|
||||||
createIndexes.forEach(it -> session.execute(CreateIndexCqlGenerator.toCql(it)));
|
createIndexes.forEach(it -> session.execute(CreateIndexCqlGenerator.toCql(it)));
|
||||||
@@ -78,8 +83,8 @@ public class IndexCreationIntegrationTests extends AbstractKeyspaceCreatingInteg
|
|||||||
public void shouldCreateSasiIndex() throws InterruptedException {
|
public void shouldCreateSasiIndex() throws InterruptedException {
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(WithSasiIndex.class);
|
BasicCassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(WithSasiIndex.class);
|
||||||
CreateTableSpecification createTable = mappingContext.getCreateTableSpecificationFor(entity);
|
CreateTableSpecification createTable = schemaFactory.getCreateTableSpecificationFor(entity);
|
||||||
List<CreateIndexSpecification> createIndexes = mappingContext.getCreateIndexSpecificationsFor(entity);
|
List<CreateIndexSpecification> createIndexes = schemaFactory.getCreateIndexSpecificationsFor(entity);
|
||||||
|
|
||||||
session.execute(CreateTableCqlGenerator.toCql(createTable));
|
session.execute(CreateTableCqlGenerator.toCql(createTable));
|
||||||
createIndexes.forEach(it -> session.execute(CreateIndexCqlGenerator.toCql(it)));
|
createIndexes.forEach(it -> session.execute(CreateIndexCqlGenerator.toCql(it)));
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
@@ -26,6 +26,11 @@ import org.springframework.data.annotation.AccessType;
|
|||||||
import org.springframework.data.annotation.AccessType.Type;
|
import org.springframework.data.annotation.AccessType.Type;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification.ColumnFunction;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification.ColumnFunction;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Indexed;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.SASI;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.NonTokenizingAnalyzed;
|
import org.springframework.data.cassandra.core.mapping.SASI.NonTokenizingAnalyzed;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.Normalization;
|
import org.springframework.data.cassandra.core.mapping.SASI.Normalization;
|
||||||
import org.springframework.data.cassandra.core.mapping.SASI.StandardAnalyzed;
|
import org.springframework.data.cassandra.core.mapping.SASI.StandardAnalyzed;
|
||||||
@@ -91,8 +96,8 @@ public class IndexSpecificationFactoryUnitTests {
|
|||||||
assertThat(simpleSasi.isCustom()).isTrue();
|
assertThat(simpleSasi.isCustom()).isTrue();
|
||||||
assertThat(simpleSasi.getUsing()).isEqualTo("org.apache.cassandra.index.sasi.SASIIndex");
|
assertThat(simpleSasi.getUsing()).isEqualTo("org.apache.cassandra.index.sasi.SASIIndex");
|
||||||
assertThat(simpleSasi.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
assertThat(simpleSasi.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
||||||
assertThat(simpleSasi.getOptions()).containsEntry("mode", "PREFIX")
|
assertThat(simpleSasi.getOptions()).containsEntry("mode", "PREFIX").doesNotContainKeys("analyzed",
|
||||||
.doesNotContainKeys("analyzed", "analyzer_class");
|
"analyzer_class");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-306
|
@Test // DATACASS-306
|
||||||
@@ -101,8 +106,7 @@ public class IndexSpecificationFactoryUnitTests {
|
|||||||
CreateIndexSpecification simpleSasi = createIndexFor(IndexedType.class, "sasiStandard");
|
CreateIndexSpecification simpleSasi = createIndexFor(IndexedType.class, "sasiStandard");
|
||||||
|
|
||||||
assertThat(simpleSasi.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
assertThat(simpleSasi.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
||||||
assertThat(simpleSasi.getOptions()).containsEntry("mode", "PREFIX")
|
assertThat(simpleSasi.getOptions()).containsEntry("mode", "PREFIX").containsEntry("analyzed", "true")
|
||||||
.containsEntry("analyzed", "true")
|
|
||||||
.containsEntry("tokenization_skip_stop_words", "false")
|
.containsEntry("tokenization_skip_stop_words", "false")
|
||||||
.containsEntry("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.StandardAnalyzer")
|
.containsEntry("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.StandardAnalyzer")
|
||||||
.containsEntry("tokenization_locale", "de");
|
.containsEntry("tokenization_locale", "de");
|
||||||
@@ -115,8 +119,7 @@ public class IndexSpecificationFactoryUnitTests {
|
|||||||
|
|
||||||
assertThat(simpleSasi.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
assertThat(simpleSasi.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
||||||
assertThat(simpleSasi.getOptions()).containsEntry("tokenization_skip_stop_words", "true")
|
assertThat(simpleSasi.getOptions()).containsEntry("tokenization_skip_stop_words", "true")
|
||||||
.containsEntry("tokenization_locale", "de")
|
.containsEntry("tokenization_locale", "de").containsEntry("tokenization_enable_stemming", "true")
|
||||||
.containsEntry("tokenization_enable_stemming", "true")
|
|
||||||
.containsEntry("tokenization_normalize_uppercase", "true")
|
.containsEntry("tokenization_normalize_uppercase", "true")
|
||||||
.doesNotContainKey("tokenization_normalize_lowercase");
|
.doesNotContainKey("tokenization_normalize_lowercase");
|
||||||
}
|
}
|
||||||
@@ -136,8 +139,7 @@ public class IndexSpecificationFactoryUnitTests {
|
|||||||
|
|
||||||
CreateIndexSpecification simpleSasi = createIndexFor(IndexedType.class, "sasiNontokenizing");
|
CreateIndexSpecification simpleSasi = createIndexFor(IndexedType.class, "sasiNontokenizing");
|
||||||
|
|
||||||
assertThat(simpleSasi.getOptions()).containsEntry("mode", "PREFIX")
|
assertThat(simpleSasi.getOptions()).containsEntry("mode", "PREFIX").containsEntry("analyzed", "true")
|
||||||
.containsEntry("analyzed", "true")
|
|
||||||
.containsEntry("case_sensitive", "true")
|
.containsEntry("case_sensitive", "true")
|
||||||
.containsEntry("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer")
|
.containsEntry("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer")
|
||||||
.doesNotContainKeys("normalize_lowercase", "normalize_uppercase");
|
.doesNotContainKeys("normalize_lowercase", "normalize_uppercase");
|
||||||
@@ -149,8 +151,7 @@ public class IndexSpecificationFactoryUnitTests {
|
|||||||
CreateIndexSpecification simpleSasi = createIndexFor(IndexedType.class, "sasiNontokenizingLowercase");
|
CreateIndexSpecification simpleSasi = createIndexFor(IndexedType.class, "sasiNontokenizingLowercase");
|
||||||
|
|
||||||
assertThat(simpleSasi.getOptions()).containsEntry("normalize_lowercase", "true")
|
assertThat(simpleSasi.getOptions()).containsEntry("normalize_lowercase", "true")
|
||||||
.containsEntry("case_sensitive", "false")
|
.containsEntry("case_sensitive", "false").doesNotContainKey("normalize_uppercase");
|
||||||
.doesNotContainKey("normalize_uppercase");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +39,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier;
|
|||||||
import com.datastax.oss.driver.api.core.cql.Row;
|
import com.datastax.oss.driver.api.core.cql.Row;
|
||||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
import com.datastax.oss.driver.api.core.type.DataTypes;
|
||||||
|
import com.datastax.oss.driver.api.core.type.TupleType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for mapped tuples through {@link MappingCassandraConverter}.
|
* Unit tests for mapped tuples through {@link MappingCassandraConverter}.
|
||||||
@@ -67,10 +68,12 @@ public class MappingCassandraConverterMappedTupleUnitTests {
|
|||||||
|
|
||||||
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(MappedTuple.class);
|
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(MappedTuple.class);
|
||||||
|
|
||||||
TupleValue value = entity.getTupleType().newValue("hello", 1);
|
CassandraColumnType type = mappingCassandraConverter.getColumnTypeResolver().resolve(entity.getTypeInformation());
|
||||||
|
|
||||||
|
TupleValue value = ((TupleType) type.getDataType()).newValue("hello", 1);
|
||||||
|
|
||||||
this.rowMock = RowMockUtil.newRowMock(column("name", "Jon Doe", DataTypes.TEXT),
|
this.rowMock = RowMockUtil.newRowMock(column("name", "Jon Doe", DataTypes.TEXT),
|
||||||
column("tuple", value, entity.getTupleType()));
|
column("tuple", value, type.getDataType()));
|
||||||
|
|
||||||
Person person = this.mappingCassandraConverter.read(Person.class, rowMock);
|
Person person = this.mappingCassandraConverter.read(Person.class, rowMock);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecif
|
|||||||
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
|
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
|
||||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||||
import org.springframework.data.cassandra.core.mapping.Element;
|
import org.springframework.data.cassandra.core.mapping.Element;
|
||||||
import org.springframework.data.cassandra.core.mapping.SimpleTupleTypeFactory;
|
|
||||||
import org.springframework.data.cassandra.core.mapping.Table;
|
import org.springframework.data.cassandra.core.mapping.Table;
|
||||||
import org.springframework.data.cassandra.core.mapping.Tuple;
|
import org.springframework.data.cassandra.core.mapping.Tuple;
|
||||||
import org.springframework.data.cassandra.core.mapping.UserDefinedType;
|
import org.springframework.data.cassandra.core.mapping.UserDefinedType;
|
||||||
@@ -105,8 +104,9 @@ public class MappingCassandraConverterTupleIntegrationTests extends AbstractSpri
|
|||||||
this.session.execute("DROP TABLE IF EXISTS person;");
|
this.session.execute("DROP TABLE IF EXISTS person;");
|
||||||
|
|
||||||
CassandraMappingContext mappingContext = converter.getMappingContext();
|
CassandraMappingContext mappingContext = converter.getMappingContext();
|
||||||
|
SchemaFactory schemaFactory = new SchemaFactory(converter);
|
||||||
|
|
||||||
CreateUserTypeSpecification createAddress = mappingContext
|
CreateUserTypeSpecification createAddress = schemaFactory
|
||||||
.getCreateUserTypeSpecificationFor(mappingContext.getRequiredPersistentEntity(AddressUserType.class));
|
.getCreateUserTypeSpecificationFor(mappingContext.getRequiredPersistentEntity(AddressUserType.class));
|
||||||
|
|
||||||
this.session.execute(CreateUserTypeCqlGenerator.toCql(createAddress));
|
this.session.execute(CreateUserTypeCqlGenerator.toCql(createAddress));
|
||||||
@@ -127,7 +127,7 @@ public class MappingCassandraConverterTupleIntegrationTests extends AbstractSpri
|
|||||||
@Test // DATACASS-651
|
@Test // DATACASS-651
|
||||||
public void shouldInsertRowWithTuple() {
|
public void shouldInsertRowWithTuple() {
|
||||||
|
|
||||||
TupleType tupleType = SimpleTupleTypeFactory.DEFAULT.create(DataTypes.TEXT, DataTypes.INT);
|
TupleType tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.INT);
|
||||||
|
|
||||||
Person person = new Person();
|
Person person = new Person();
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ public class MappingCassandraConverterTupleIntegrationTests extends AbstractSpri
|
|||||||
|
|
||||||
person.setMapOfTuples(Collections.singletonMap("foo", tuple));
|
person.setMapOfTuples(Collections.singletonMap("foo", tuple));
|
||||||
|
|
||||||
TupleType tupleType = SimpleTupleTypeFactory.DEFAULT.create(DataTypes.TEXT, DataTypes.INT);
|
TupleType tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.INT);
|
||||||
person.setMapOfTupleValues(Collections.singletonMap("mykey", tupleType.newValue("hello", 42)));
|
person.setMapOfTupleValues(Collections.singletonMap("mykey", tupleType.newValue("hello", 42)));
|
||||||
|
|
||||||
StatementFactory statementFactory = new StatementFactory(new UpdateMapper(converter));
|
StatementFactory statementFactory = new StatementFactory(new UpdateMapper(converter));
|
||||||
|
|||||||
@@ -218,7 +218,9 @@ public class MappingCassandraConverterUDTIntegrationTests extends AbstractSpring
|
|||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = converter.getMappingContext()
|
CassandraPersistentEntity<?> persistentEntity = converter.getMappingContext()
|
||||||
.getRequiredPersistentEntity(AddressUserType.class);
|
.getRequiredPersistentEntity(AddressUserType.class);
|
||||||
UdtValue udtValue = persistentEntity.getUserType().newValue();
|
com.datastax.oss.driver.api.core.type.UserDefinedType udtType = (com.datastax.oss.driver.api.core.type.UserDefinedType) converter
|
||||||
|
.getColumnTypeResolver().resolve(persistentEntity.getTypeInformation()).getDataType();
|
||||||
|
UdtValue udtValue = udtType.newValue();
|
||||||
udtValue.setString("zip", "69469");
|
udtValue.setString("zip", "69469");
|
||||||
udtValue.setString("city", "Weinheim");
|
udtValue.setString("city", "Weinheim");
|
||||||
udtValue.setList("streetlines", Arrays.asList("Heckenpfad", "14"), String.class);
|
udtValue.setList("streetlines", Arrays.asList("Heckenpfad", "14"), String.class);
|
||||||
@@ -256,7 +258,10 @@ public class MappingCassandraConverterUDTIntegrationTests extends AbstractSpring
|
|||||||
CassandraPersistentEntity<?> persistentEntity = converter.getMappingContext()
|
CassandraPersistentEntity<?> persistentEntity = converter.getMappingContext()
|
||||||
.getRequiredPersistentEntity(AddressUserType.class);
|
.getRequiredPersistentEntity(AddressUserType.class);
|
||||||
|
|
||||||
UdtValue udtValue = persistentEntity.getUserType().newValue();
|
com.datastax.oss.driver.api.core.type.UserDefinedType udtType = (com.datastax.oss.driver.api.core.type.UserDefinedType) converter
|
||||||
|
.getColumnTypeResolver().resolve(persistentEntity.getTypeInformation()).getDataType();
|
||||||
|
|
||||||
|
UdtValue udtValue = udtType.newValue();
|
||||||
udtValue.setString("zip", "69469");
|
udtValue.setString("zip", "69469");
|
||||||
udtValue.setString("city", "Weinheim");
|
udtValue.setString("city", "Weinheim");
|
||||||
udtValue.setList("streetlines", Arrays.asList("Heckenpfad", "14"), String.class);
|
udtValue.setList("streetlines", Arrays.asList("Heckenpfad", "14"), String.class);
|
||||||
|
|||||||
@@ -352,8 +352,7 @@ public class QueryMapperUnitTests {
|
|||||||
Filter mappedObject = this.queryMapper.getMappedObject(filter,
|
Filter mappedObject = this.queryMapper.getMappedObject(filter,
|
||||||
this.mappingContext.getRequiredPersistentEntity(Person.class));
|
this.mappingContext.getRequiredPersistentEntity(Person.class));
|
||||||
|
|
||||||
TupleValue tupleValue = this.mappingContext.getRequiredPersistentEntity(MappedTuple.class).getTupleType()
|
TupleValue tupleValue = DataTypes.tupleOf(DataTypes.TEXT).newValue();
|
||||||
.newValue();
|
|
||||||
|
|
||||||
tupleValue.setString(0, "foo");
|
tupleValue.setString(0, "foo");
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,10 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.convert;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.springframework.data.cassandra.core.mapping.CassandraType.*;
|
import static org.springframework.data.cassandra.core.mapping.CassandraType.*;
|
||||||
|
|
||||||
@@ -24,10 +25,12 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -35,42 +38,320 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
|
import org.springframework.data.cassandra.core.cql.Ordering;
|
||||||
|
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.ColumnSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.ColumnSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification.ColumnFunction;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Element;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Indexed;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Table;
|
||||||
|
import org.springframework.data.cassandra.core.mapping.Tuple;
|
||||||
import org.springframework.data.cassandra.domain.AllPossibleTypes;
|
import org.springframework.data.cassandra.domain.AllPossibleTypes;
|
||||||
|
import org.springframework.data.cassandra.support.UserDefinedTypeBuilder;
|
||||||
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
|
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||||
import com.datastax.oss.driver.api.core.type.DataType;
|
import com.datastax.oss.driver.api.core.type.DataType;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
import com.datastax.oss.driver.api.core.type.DataTypes;
|
||||||
import com.datastax.oss.driver.api.core.type.ListType;
|
import com.datastax.oss.driver.api.core.type.ListType;
|
||||||
import com.datastax.oss.driver.api.core.type.SetType;
|
import com.datastax.oss.driver.api.core.type.SetType;
|
||||||
|
import com.datastax.oss.driver.api.core.type.TupleType;
|
||||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||||
import com.datastax.oss.protocol.internal.ProtocolConstants;
|
import com.datastax.oss.protocol.internal.ProtocolConstants;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link CassandraMappingContext} targeted on {@link CreateTableSpecification}.
|
* Unit tests for {@link SchemaFactory}.
|
||||||
*
|
*
|
||||||
|
* @author Matthew T. Adams
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Vagif Zeynalov
|
|
||||||
* @soundtrack Black Rose - Volbeat
|
|
||||||
*/
|
*/
|
||||||
public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
public class SchemaFactoryUnitTests {
|
||||||
|
|
||||||
private CassandraMappingContext ctx = new CassandraMappingContext();
|
CassandraMappingContext ctx = new CassandraMappingContext();
|
||||||
|
SchemaFactory schemaFactory;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void before() {
|
||||||
|
|
||||||
List<Converter<?, ?>> converters = new ArrayList<>();
|
List<Converter<?, ?>> converters = new ArrayList<>();
|
||||||
converters.add(new PersonReadConverter());
|
converters.add(new PersonReadConverter());
|
||||||
converters.add(new PersonWriteConverter());
|
converters.add(new PersonWriteConverter());
|
||||||
|
converters.add(HumanToStringConverter.INSTANCE);
|
||||||
|
|
||||||
CassandraCustomConversions customConversions = new CassandraCustomConversions(converters);
|
CassandraCustomConversions customConversions = new CassandraCustomConversions(converters);
|
||||||
ctx.setCustomConversions(customConversions);
|
ctx.setCustomConversions(customConversions);
|
||||||
|
schemaFactory = new SchemaFactory(new MappingCassandraConverter(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-340
|
||||||
|
public void createdTableSpecificationShouldConsiderClusterColumnOrdering() {
|
||||||
|
|
||||||
|
CassandraPersistentEntity<?> persistentEntity = ctx
|
||||||
|
.getRequiredPersistentEntity(EntityWithOrderedClusteredColumns.class);
|
||||||
|
|
||||||
|
CreateTableSpecification tableSpecification = schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
|
|
||||||
|
assertThat(tableSpecification.getPartitionKeyColumns()).hasSize(1);
|
||||||
|
assertThat(tableSpecification.getClusteredKeyColumns()).hasSize(3);
|
||||||
|
|
||||||
|
ColumnSpecification breed = tableSpecification.getClusteredKeyColumns().get(0);
|
||||||
|
assertThat(breed.getName().toString()).isEqualTo("breed");
|
||||||
|
assertThat(breed.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
||||||
|
|
||||||
|
ColumnSpecification color = tableSpecification.getClusteredKeyColumns().get(1);
|
||||||
|
assertThat(color.getName().toString()).isEqualTo("color");
|
||||||
|
assertThat(color.getOrdering()).isEqualTo(Ordering.DESCENDING);
|
||||||
|
|
||||||
|
ColumnSpecification kind = tableSpecification.getClusteredKeyColumns().get(2);
|
||||||
|
assertThat(kind.getName().toString()).isEqualTo("kind");
|
||||||
|
assertThat(kind.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-340
|
||||||
|
public void createdTableSpecificationShouldConsiderPrimaryKeyClassClusterColumnOrdering() {
|
||||||
|
|
||||||
|
CassandraPersistentEntity<?> persistentEntity = ctx
|
||||||
|
.getRequiredPersistentEntity(EntityWithPrimaryKeyWithOrderedClusteredColumns.class);
|
||||||
|
|
||||||
|
CreateTableSpecification tableSpecification = schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
|
|
||||||
|
assertThat(tableSpecification.getPartitionKeyColumns()).hasSize(1);
|
||||||
|
assertThat(tableSpecification.getClusteredKeyColumns()).hasSize(3);
|
||||||
|
|
||||||
|
ColumnSpecification breed = tableSpecification.getClusteredKeyColumns().get(0);
|
||||||
|
assertThat(breed.getName().toString()).isEqualTo("breed");
|
||||||
|
assertThat(breed.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
||||||
|
|
||||||
|
ColumnSpecification color = tableSpecification.getClusteredKeyColumns().get(1);
|
||||||
|
assertThat(color.getName().toString()).isEqualTo("color");
|
||||||
|
assertThat(color.getOrdering()).isEqualTo(Ordering.DESCENDING);
|
||||||
|
|
||||||
|
ColumnSpecification kind = tableSpecification.getClusteredKeyColumns().get(2);
|
||||||
|
assertThat(kind.getName().toString()).isEqualTo("kind");
|
||||||
|
assertThat(kind.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-487
|
||||||
|
public void shouldCreateTableForMappedAndConvertedColumn() {
|
||||||
|
|
||||||
|
UserDefinedType mappedudt = UserDefinedTypeBuilder.forName("mappedudt").withField("foo", DataTypes.ASCII).build();
|
||||||
|
|
||||||
|
this.ctx.setUserTypeResolver(typeName -> mappedudt);
|
||||||
|
|
||||||
|
CassandraPersistentEntity<?> persistentEntity = this.ctx.getRequiredPersistentEntity(WithMapOfMixedTypes.class);
|
||||||
|
|
||||||
|
CreateTableSpecification tableSpecification = schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
|
|
||||||
|
assertThat(tableSpecification.getColumns()).hasSize(2);
|
||||||
|
|
||||||
|
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
||||||
|
|
||||||
|
assertThat(column.getType().asCql(true, true)).isEqualTo("map<frozen<mappedudt>, list<text>>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrimaryKeyClass
|
||||||
|
private static class CompositePrimaryKeyClassWithProperties implements Serializable {
|
||||||
|
|
||||||
|
String firstname;
|
||||||
|
String lastname;
|
||||||
|
|
||||||
|
@PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.PARTITIONED)
|
||||||
|
public String getFirstname() {
|
||||||
|
return firstname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstname(String firstname) {
|
||||||
|
this.firstname = firstname;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrimaryKeyColumn(name = "mylastname", ordinal = 2, type = PrimaryKeyType.CLUSTERED)
|
||||||
|
public String getLastname() {
|
||||||
|
return lastname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastname(String lastname) {
|
||||||
|
this.lastname = lastname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class EntityWithOrderedClusteredColumns {
|
||||||
|
|
||||||
|
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) String species;
|
||||||
|
@PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.ASCENDING) String breed;
|
||||||
|
@PrimaryKeyColumn(ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING) String color;
|
||||||
|
@PrimaryKeyColumn(ordinal = 3, type = PrimaryKeyType.CLUSTERED) String kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrimaryKeyClass
|
||||||
|
static class PrimaryKeyWithOrderedClusteredColumns implements Serializable {
|
||||||
|
|
||||||
|
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) String species;
|
||||||
|
@PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.ASCENDING) String breed;
|
||||||
|
@PrimaryKeyColumn(ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING) String color;
|
||||||
|
@PrimaryKeyColumn(ordinal = 3, type = PrimaryKeyType.CLUSTERED) String kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
private static class EntityWithPrimaryKeyWithOrderedClusteredColumns {
|
||||||
|
|
||||||
|
@PrimaryKey PrimaryKeyWithOrderedClusteredColumns key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-213
|
||||||
|
public void createIndexShouldConsiderAnnotatedProperties() {
|
||||||
|
|
||||||
|
List<CreateIndexSpecification> specifications = schemaFactory
|
||||||
|
.getCreateIndexSpecificationsFor(ctx.getRequiredPersistentEntity(IndexedType.class));
|
||||||
|
|
||||||
|
CreateIndexSpecification firstname = getSpecificationFor("first_name", specifications);
|
||||||
|
|
||||||
|
assertThat(firstname.getColumnName()).isEqualTo(CqlIdentifier.fromCql("first_name"));
|
||||||
|
assertThat(firstname.getTableName()).isEqualTo(CqlIdentifier.fromCql("indexedtype"));
|
||||||
|
assertThat(firstname.getName()).isEqualTo(CqlIdentifier.fromCql("my_index"));
|
||||||
|
assertThat(firstname.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
||||||
|
|
||||||
|
CreateIndexSpecification phoneNumbers = getSpecificationFor("phoneNumbers", specifications);
|
||||||
|
|
||||||
|
assertThat(phoneNumbers.getColumnName()).isEqualTo(CqlIdentifier.fromCql("phoneNumbers"));
|
||||||
|
assertThat(phoneNumbers.getTableName()).isEqualTo(CqlIdentifier.fromCql("indexedtype"));
|
||||||
|
assertThat(phoneNumbers.getName()).isNull();
|
||||||
|
assertThat(phoneNumbers.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-213
|
||||||
|
public void createIndexForClusteredPrimaryKeyShouldConsiderAnnotatedAccessors() {
|
||||||
|
|
||||||
|
List<CreateIndexSpecification> specifications = schemaFactory
|
||||||
|
.getCreateIndexSpecificationsFor(ctx.getRequiredPersistentEntity(CompositeKeyEntity.class));
|
||||||
|
|
||||||
|
CreateIndexSpecification entries = getSpecificationFor("last_name", specifications);
|
||||||
|
|
||||||
|
assertThat(entries.getColumnName()).isEqualTo(CqlIdentifier.fromCql("last_name"));
|
||||||
|
assertThat(entries.getTableName()).isEqualTo(CqlIdentifier.fromCql("compositekeyentity"));
|
||||||
|
assertThat(entries.getName()).isEqualTo(CqlIdentifier.fromCql("my_index"));
|
||||||
|
assertThat(entries.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-284, DATACASS-651
|
||||||
|
public void shouldRejectUntypedTuples() {
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> this.schemaFactory
|
||||||
|
.getCreateTableSpecificationFor(this.ctx.getRequiredPersistentEntity(UntypedTupleEntity.class)))
|
||||||
|
.isInstanceOf(MappingException.class);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> this.schemaFactory
|
||||||
|
.getCreateTableSpecificationFor(this.ctx.getRequiredPersistentEntity(UntypedTupleMapEntity.class)))
|
||||||
|
.isInstanceOf(MappingException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-284
|
||||||
|
public void shouldCreateTableForTypedTupleType() {
|
||||||
|
|
||||||
|
CreateTableSpecification tableSpecification = this.schemaFactory
|
||||||
|
.getCreateTableSpecificationFor(this.ctx.getRequiredPersistentEntity(TypedTupleEntity.class));
|
||||||
|
|
||||||
|
assertThat(tableSpecification.getColumns()).hasSize(2);
|
||||||
|
|
||||||
|
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
||||||
|
|
||||||
|
assertThat(column.getType()).isInstanceOf(TupleType.class);
|
||||||
|
assertThat(column.getType()).isEqualTo(DataTypes.tupleOf(DataTypes.TEXT, DataTypes.BIGINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-651
|
||||||
|
public void shouldCreateTableForEntityWithMapOfTuples() {
|
||||||
|
|
||||||
|
CreateTableSpecification tableSpecification = this.schemaFactory
|
||||||
|
.getCreateTableSpecificationFor(this.ctx.getRequiredPersistentEntity(EntityWithMapOfTuples.class));
|
||||||
|
|
||||||
|
assertThat(tableSpecification.getColumns()).hasSize(2);
|
||||||
|
|
||||||
|
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
||||||
|
assertThat(column.getName()).isEqualTo(CqlIdentifier.fromCql("map"));
|
||||||
|
assertThat(column.getType().asCql(true, true)).isEqualTo("map<text, frozen<tuple<mappedudt, human_udt, text>>>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CreateIndexSpecification getSpecificationFor(String column,
|
||||||
|
List<CreateIndexSpecification> specifications) {
|
||||||
|
|
||||||
|
return specifications.stream().filter(it -> it.getColumnName().equals(CqlIdentifier.fromCql(column))).findFirst()
|
||||||
|
.orElseThrow(() -> new NoSuchElementException(column));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IndexedType {
|
||||||
|
|
||||||
|
@PrimaryKeyColumn("first_name") @Indexed("my_index") String firstname;
|
||||||
|
|
||||||
|
@Indexed List<String> phoneNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrimaryKeyClass
|
||||||
|
static class CompositeKeyWithIndex {
|
||||||
|
|
||||||
|
@PrimaryKeyColumn(value = "first_name", type = PrimaryKeyType.PARTITIONED) String firstname;
|
||||||
|
@PrimaryKeyColumn("last_name") @Indexed("my_index") String lastname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CompositeKeyEntity {
|
||||||
|
|
||||||
|
@PrimaryKey CompositeKeyWithIndex key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class InvalidMapIndex {
|
||||||
|
|
||||||
|
@Indexed Map<@Indexed String, String> mixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-506
|
||||||
|
public void shouldCreatedUserTypeSpecificationsWithAnnotatedTypeName() {
|
||||||
|
|
||||||
|
assertThat(schemaFactory.getCreateUserTypeSpecificationFor(ctx.getRequiredPersistentEntity(WithUdt.class)))
|
||||||
|
.isNotNull();
|
||||||
|
assertThat(schemaFactory.getCreateUserTypeSpecificationFor(ctx.getRequiredPersistentEntity(Nested.class)))
|
||||||
|
.isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-172
|
||||||
|
public void createTableForComplexPrimaryKeyShouldFail() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
schemaFactory
|
||||||
|
.getCreateTableSpecificationFor(ctx.getRequiredPersistentEntity(EntityWithComplexPrimaryKeyColumn.class));
|
||||||
|
fail("Missing MappingException");
|
||||||
|
} catch (MappingException e) {
|
||||||
|
assertThat(e).hasMessageContaining(
|
||||||
|
"Cannot resolve DataType for type [class java.lang.Object] for property [complexObject]");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
schemaFactory.getCreateTableSpecificationFor(ctx.getRequiredPersistentEntity(EntityWithComplexId.class));
|
||||||
|
fail("Missing MappingException");
|
||||||
|
} catch (MappingException e) {
|
||||||
|
assertThat(e).hasMessageContaining(
|
||||||
|
"Cannot resolve DataType for type [class java.lang.Object] for property [complexObject]");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
schemaFactory.getCreateTableSpecificationFor(
|
||||||
|
ctx.getRequiredPersistentEntity(EntityWithPrimaryKeyClassWithComplexId.class));
|
||||||
|
fail("Missing MappingException");
|
||||||
|
} catch (MappingException e) {
|
||||||
|
assertThat(e).hasMessageContaining(
|
||||||
|
"Cannot resolve DataType for type [class java.lang.Object] for property [complexObject]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-296
|
@Test // DATACASS-296
|
||||||
@@ -78,7 +359,7 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(Employee.class);
|
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(Employee.class);
|
||||||
|
|
||||||
CreateTableSpecification specification = ctx.getCreateTableSpecificationFor(persistentEntity);
|
CreateTableSpecification specification = schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
|
|
||||||
assertThat(getColumnType("human", specification)).isEqualTo(DataTypes.TEXT);
|
assertThat(getColumnType("human", specification)).isEqualTo(DataTypes.TEXT);
|
||||||
|
|
||||||
@@ -102,7 +383,7 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(Employee.class);
|
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(Employee.class);
|
||||||
|
|
||||||
CreateTableSpecification specification = ctx.getCreateTableSpecificationFor(persistentEntity);
|
CreateTableSpecification specification = schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
|
|
||||||
assertThat(getColumnType("floater", specification)).isEqualTo(DataTypes.FLOAT);
|
assertThat(getColumnType("floater", specification)).isEqualTo(DataTypes.FLOAT);
|
||||||
|
|
||||||
@@ -248,26 +529,6 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
@Test // DATACASS-172
|
@Test // DATACASS-172
|
||||||
public void columnsShouldMapToUdt() {
|
public void columnsShouldMapToUdt() {
|
||||||
|
|
||||||
UserDefinedType human_udt = new CassandraMappingContext.ShallowUserDefinedType("human_udt", false);
|
|
||||||
UserDefinedType species_udt = new CassandraMappingContext.ShallowUserDefinedType("species_udt", false);
|
|
||||||
UserDefinedType peeps_udt = new CassandraMappingContext.ShallowUserDefinedType("peeps_udt", false);
|
|
||||||
|
|
||||||
ctx.setUserTypeResolver(typeName -> {
|
|
||||||
|
|
||||||
if (typeName.equals(human_udt.getName())) {
|
|
||||||
return human_udt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeName.equals(species_udt.getName())) {
|
|
||||||
return species_udt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeName.equals(peeps_udt.getName())) {
|
|
||||||
return peeps_udt;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
CreateTableSpecification specification = getCreateTableSpecificationFor(WithUdtFields.class);
|
CreateTableSpecification specification = getCreateTableSpecificationFor(WithUdtFields.class);
|
||||||
|
|
||||||
assertThat(getColumnType("human", specification).asCql(false, true)).isEqualTo("human_udt");
|
assertThat(getColumnType("human", specification).asCql(false, true)).isEqualTo("human_udt");
|
||||||
@@ -278,7 +539,7 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
@Test // DATACASS-172
|
@Test // DATACASS-172
|
||||||
public void columnsShouldMapToMappedUserType() {
|
public void columnsShouldMapToMappedUserType() {
|
||||||
|
|
||||||
UserDefinedType mappedUdt = new CassandraMappingContext.ShallowUserDefinedType("mappedudt", true);
|
UserDefinedType mappedUdt = new SchemaFactory.ShallowUserDefinedType("mappedudt", true);
|
||||||
|
|
||||||
ctx.setUserTypeResolver(typeName -> {
|
ctx.setUserTypeResolver(typeName -> {
|
||||||
|
|
||||||
@@ -336,7 +597,8 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
CqlIdentifier customTableName = CqlIdentifier.fromCql("my_custom_came");
|
CqlIdentifier customTableName = CqlIdentifier.fromCql("my_custom_came");
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(Employee.class);
|
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(Employee.class);
|
||||||
CreateTableSpecification specification = ctx.getCreateTableSpecificationFor(customTableName, persistentEntity);
|
CreateTableSpecification specification = schemaFactory.getCreateTableSpecificationFor(persistentEntity,
|
||||||
|
customTableName);
|
||||||
|
|
||||||
assertThat(specification).isNotNull();
|
assertThat(specification).isNotNull();
|
||||||
assertThat(specification.getName()).isEqualTo(customTableName);
|
assertThat(specification.getName()).isEqualTo(customTableName);
|
||||||
@@ -348,7 +610,7 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
ctx.setCustomConversions(customConversions);
|
ctx.setCustomConversions(customConversions);
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(persistentEntityClass);
|
CassandraPersistentEntity<?> persistentEntity = ctx.getRequiredPersistentEntity(persistentEntityClass);
|
||||||
return ctx.getCreateTableSpecificationFor(persistentEntity);
|
return schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType getColumnType(String columnName, CreateTableSpecification specification) {
|
private DataType getColumnType(String columnName, CreateTableSpecification specification) {
|
||||||
@@ -405,10 +667,8 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
@Id String id;
|
@Id String id;
|
||||||
|
|
||||||
@CassandraType(type = Name.UDT, userTypeName = "human_udt") UdtValue human;
|
@CassandraType(type = Name.UDT, userTypeName = "human_udt") UdtValue human;
|
||||||
@CassandraType(type = Name.LIST, typeArguments = Name.UDT,
|
@CassandraType(type = Name.LIST, typeArguments = Name.UDT, userTypeName = "species_udt") List<UdtValue> friends;
|
||||||
userTypeName = "species_udt") List<UdtValue> friends;
|
@CassandraType(type = Name.SET, typeArguments = Name.UDT, userTypeName = "peeps_udt") Set<UdtValue> people;
|
||||||
@CassandraType(type = Name.SET, typeArguments = Name.UDT,
|
|
||||||
userTypeName = "peeps_udt") Set<UdtValue> people;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -473,4 +733,98 @@ public class CreateTableSpecificationBasicCassandraMappingContextUnitTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
private static class InvalidEntityWithIdAndPrimaryKeyColumn {
|
||||||
|
@Id String foo;
|
||||||
|
@PrimaryKeyColumn String bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class EntityWithComplexPrimaryKeyColumn {
|
||||||
|
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) Object complexObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class EntityWithComplexId {
|
||||||
|
@Id Object complexObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrimaryKeyClass
|
||||||
|
static class PrimaryKeyClassWithComplexId {
|
||||||
|
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) Object complexObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class EntityWithPrimaryKeyClassWithComplexId {
|
||||||
|
@Id PrimaryKeyClassWithComplexId primaryKeyClassWithComplexId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
private static class X {
|
||||||
|
@PrimaryKey String key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
private static class Y {
|
||||||
|
@PrimaryKey String key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
private static class WithUdt {
|
||||||
|
@Id String id;
|
||||||
|
@CassandraType(type = Name.UDT, userTypeName = "mappedudt") UdtValue udtValue;
|
||||||
|
@CassandraType(type = Name.UDT, userTypeName = "NestedType") Nested nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
private static class WithMapOfMixedTypes {
|
||||||
|
@Id String id;
|
||||||
|
Map<MappedUdt, List<Human>> people;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HumanToStringConverter implements Converter<Human, String> {
|
||||||
|
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(Human source) {
|
||||||
|
return "hello";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@org.springframework.data.cassandra.core.mapping.UserDefinedType(value = "NestedType")
|
||||||
|
public static class Nested {
|
||||||
|
String s1;
|
||||||
|
@CassandraType(type = Name.UDT, userTypeName = "AnotherNestedType") AnotherNested anotherNested;
|
||||||
|
}
|
||||||
|
|
||||||
|
@org.springframework.data.cassandra.core.mapping.UserDefinedType(value = "AnotherNestedType")
|
||||||
|
public static class AnotherNested {
|
||||||
|
String str;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class TypedTupleEntity {
|
||||||
|
@Id String id;
|
||||||
|
@CassandraType(type = Name.TUPLE, typeArguments = { Name.VARCHAR, Name.BIGINT }) TupleValue typed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class EntityWithMapOfTuples {
|
||||||
|
@Id String id;
|
||||||
|
Map<String, MappedTuple> map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class UntypedTupleEntity {
|
||||||
|
@Id String id;
|
||||||
|
TupleValue untyped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Table
|
||||||
|
static class UntypedTupleMapEntity {
|
||||||
|
@Id String id;
|
||||||
|
Map<String, TupleValue> untyped;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,6 @@ import java.lang.reflect.Field;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ import org.springframework.data.util.ClassTypeInformation;
|
|||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.protocol.internal.ProtocolConstants;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link BasicCassandraPersistentProperty}.
|
* Unit tests for {@link BasicCassandraPersistentProperty}.
|
||||||
@@ -102,26 +100,6 @@ public class BasicCassandraPersistentPropertyUnitTests {
|
|||||||
assertThat(persistentProperty.isPrimaryKeyColumn()).isTrue();
|
assertThat(persistentProperty.isPrimaryKeyColumn()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-259
|
|
||||||
public void shouldConsiderComposedCassandraTypeAnnotation() {
|
|
||||||
|
|
||||||
CassandraPersistentProperty persistentProperty = getPropertyFor(TypeWithComposedCassandraTypeAnnotation.class,
|
|
||||||
"column");
|
|
||||||
|
|
||||||
assertThat(persistentProperty.getDataType().getProtocolCode()).isEqualTo(ProtocolConstants.DataType.COUNTER);
|
|
||||||
assertThat(persistentProperty.findAnnotation(CassandraType.class)).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-375
|
|
||||||
public void UuidshouldMapToUUIDByDefault() {
|
|
||||||
|
|
||||||
CassandraPersistentProperty uuidProperty = getPropertyFor(TypeWithUUIDColumn.class, "uuid");
|
|
||||||
CassandraPersistentProperty timeUUIDProperty = getPropertyFor(TypeWithUUIDColumn.class, "timeUUID");
|
|
||||||
|
|
||||||
assertThat(uuidProperty.getDataType().getProtocolCode()).isEqualTo(ProtocolConstants.DataType.UUID);
|
|
||||||
assertThat(timeUUIDProperty.getDataType().getProtocolCode()).isEqualTo(ProtocolConstants.DataType.TIMEUUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-568
|
@Test // DATACASS-568
|
||||||
public void shouldFindAnnotationInMapTypes() {
|
public void shouldFindAnnotationInMapTypes() {
|
||||||
|
|
||||||
@@ -144,6 +122,15 @@ public class BasicCassandraPersistentPropertyUnitTests {
|
|||||||
assertThat(findAnnotatedType(TypeWithCollections.class, "subtype")).isNull();
|
assertThat(findAnnotatedType(TypeWithCollections.class, "subtype")).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATACASS-259
|
||||||
|
public void shouldConsiderComposedCassandraTypeAnnotation() {
|
||||||
|
|
||||||
|
CassandraPersistentProperty persistentProperty = getPropertyFor(TypeWithComposedCassandraTypeAnnotation.class,
|
||||||
|
"column");
|
||||||
|
|
||||||
|
assertThat(persistentProperty.findAnnotation(CassandraType.class)).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
private AnnotatedType findAnnotatedType(Class<?> type, String parameterized) {
|
private AnnotatedType findAnnotatedType(Class<?> type, String parameterized) {
|
||||||
return getPropertyFor(TypeWithMaps.class, parameterized).findAnnotatedType(Indexed.class);
|
return getPropertyFor(TypeWithMaps.class, parameterized).findAnnotatedType(Indexed.class);
|
||||||
}
|
}
|
||||||
@@ -221,13 +208,6 @@ public class BasicCassandraPersistentPropertyUnitTests {
|
|||||||
@ComposedCassandraTypeAnnotation String column;
|
@ComposedCassandraTypeAnnotation String column;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TypeWithUUIDColumn {
|
|
||||||
|
|
||||||
UUID uuid;
|
|
||||||
|
|
||||||
@CassandraType(type = Name.TIMEUUID) UUID timeUUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TypeWithMaps {
|
static class TypeWithMaps {
|
||||||
|
|
||||||
Map<String, String> parameterized;
|
Map<String, String> parameterized;
|
||||||
|
|||||||
@@ -16,24 +16,17 @@
|
|||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import org.springframework.data.annotation.Transient;
|
import org.springframework.data.annotation.Transient;
|
||||||
import org.springframework.data.mapping.MappingException;
|
import org.springframework.data.mapping.MappingException;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
|
||||||
import com.datastax.oss.driver.internal.core.type.DefaultTupleType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link BasicCassandraPersistentTupleEntity}.
|
* Unit tests for {@link BasicCassandraPersistentTupleEntity}.
|
||||||
*
|
*
|
||||||
@@ -44,13 +37,6 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
|
|||||||
|
|
||||||
CassandraMappingContext mappingContext = new CassandraMappingContext();
|
CassandraMappingContext mappingContext = new CassandraMappingContext();
|
||||||
|
|
||||||
@Mock TupleTypeFactory tupleTypeFactory;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
this.mappingContext.setTupleTypeFactory(tupleTypeFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-523
|
@Test // DATACASS-523
|
||||||
public void shouldCreatePersistentTupleEntity() {
|
public void shouldCreatePersistentTupleEntity() {
|
||||||
|
|
||||||
@@ -75,21 +61,6 @@ public class BasicCassandraPersistentTupleEntityUnitTests {
|
|||||||
assertThat(propertyNames).containsSequence("street", "city", "sortOrder");
|
assertThat(propertyNames).containsSequence("street", "city", "sortOrder");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-523
|
|
||||||
public void shouldCreateTupleType() {
|
|
||||||
|
|
||||||
when(this.tupleTypeFactory.create(anyList()))
|
|
||||||
.thenReturn(new DefaultTupleType(Arrays.asList(DataTypes.TEXT, DataTypes.TEXT, DataTypes.INT)));
|
|
||||||
|
|
||||||
BasicCassandraPersistentEntity<?> entity = this.mappingContext.getRequiredPersistentEntity(Address.class);
|
|
||||||
|
|
||||||
entity.verify();
|
|
||||||
|
|
||||||
entity.getTupleType();
|
|
||||||
|
|
||||||
verify(tupleTypeFactory).create(Arrays.asList(DataTypes.TEXT, DataTypes.TEXT, DataTypes.INT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-523
|
@Test // DATACASS-523
|
||||||
public void shouldReportDuplicateMappings() {
|
public void shouldReportDuplicateMappings() {
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.cassandra.core.mapping;
|
package org.springframework.data.cassandra.core.mapping;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import org.springframework.data.mapping.model.Property;
|
import org.springframework.data.mapping.model.Property;
|
||||||
@@ -37,8 +36,6 @@ import org.springframework.util.ReflectionUtils;
|
|||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class BasicCassandraPersistentTuplePropertyUnitTests {
|
public class BasicCassandraPersistentTuplePropertyUnitTests {
|
||||||
|
|
||||||
@Mock TupleTypeFactory tupleTypeFactory;
|
|
||||||
|
|
||||||
@Test // DATACASS-523
|
@Test // DATACASS-523
|
||||||
public void mappedTupleShouldNotReportColumnName() {
|
public void mappedTupleShouldNotReportColumnName() {
|
||||||
|
|
||||||
@@ -64,7 +61,7 @@ public class BasicCassandraPersistentTuplePropertyUnitTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private <T> BasicCassandraPersistentEntity<T> getEntity(Class<T> type) {
|
private <T> BasicCassandraPersistentEntity<T> getEntity(Class<T> type) {
|
||||||
return new BasicCassandraPersistentTupleEntity<>(ClassTypeInformation.from(type), tupleTypeFactory);
|
return new BasicCassandraPersistentTupleEntity<>(ClassTypeInformation.from(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Tuple
|
@Tuple
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.util.List;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.data.cassandra.core.convert.SchemaFactory;
|
||||||
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.ColumnSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.ColumnSpecification;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
||||||
@@ -46,6 +47,8 @@ public class CassandraCompositePrimaryKeyUnitTests {
|
|||||||
|
|
||||||
CassandraMappingContext context;
|
CassandraMappingContext context;
|
||||||
|
|
||||||
|
SchemaFactory schemaFactory;
|
||||||
|
|
||||||
CassandraPersistentEntity<?> entity;
|
CassandraPersistentEntity<?> entity;
|
||||||
|
|
||||||
CassandraPersistentEntity<?> key;
|
CassandraPersistentEntity<?> key;
|
||||||
@@ -54,6 +57,7 @@ public class CassandraCompositePrimaryKeyUnitTests {
|
|||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
context = new CassandraMappingContext();
|
context = new CassandraMappingContext();
|
||||||
|
schemaFactory = new SchemaFactory(context, context.getCustomConversions(), context.getCodecRegistry());
|
||||||
entity = context.getRequiredPersistentEntity(ClassTypeInformation.from(TypeWithCompositeKey.class));
|
entity = context.getRequiredPersistentEntity(ClassTypeInformation.from(TypeWithCompositeKey.class));
|
||||||
key = context.getRequiredPersistentEntity(ClassTypeInformation.from(CompositeKey.class));
|
key = context.getRequiredPersistentEntity(ClassTypeInformation.from(CompositeKey.class));
|
||||||
}
|
}
|
||||||
@@ -68,7 +72,7 @@ public class CassandraCompositePrimaryKeyUnitTests {
|
|||||||
assertThat(property.isIdProperty()).isTrue();
|
assertThat(property.isIdProperty()).isTrue();
|
||||||
assertThat(property.isCompositePrimaryKey()).isTrue();
|
assertThat(property.isCompositePrimaryKey()).isTrue();
|
||||||
|
|
||||||
CreateTableSpecification spec = context.getCreateTableSpecificationFor(entity);
|
CreateTableSpecification spec = schemaFactory.getCreateTableSpecificationFor(entity);
|
||||||
|
|
||||||
List<ColumnSpecification> partitionKeyColumns = spec.getPartitionKeyColumns();
|
List<ColumnSpecification> partitionKeyColumns = spec.getPartitionKeyColumns();
|
||||||
assertThat(partitionKeyColumns).hasSize(1);
|
assertThat(partitionKeyColumns).hasSize(1);
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import static org.mockito.Mockito.*;
|
|||||||
import static org.springframework.data.cassandra.core.mapping.CassandraType.*;
|
import static org.springframework.data.cassandra.core.mapping.CassandraType.*;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -35,25 +33,14 @@ import org.springframework.data.annotation.Id;
|
|||||||
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
|
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
|
||||||
import org.springframework.data.cassandra.core.cql.Ordering;
|
import org.springframework.data.cassandra.core.cql.Ordering;
|
||||||
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.ColumnSpecification;
|
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification.ColumnFunction;
|
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
|
||||||
import org.springframework.data.cassandra.domain.AllPossibleTypes;
|
|
||||||
import org.springframework.data.cassandra.support.UserDefinedTypeBuilder;
|
|
||||||
import org.springframework.data.convert.WritingConverter;
|
|
||||||
import org.springframework.data.mapping.MappingException;
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
|
||||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||||
import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
|
import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
|
||||||
import com.datastax.oss.driver.api.core.type.MapType;
|
|
||||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
|
||||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||||
import com.datastax.oss.driver.internal.core.type.DefaultTupleType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link CassandraMappingContext}.
|
* Unit tests for {@link CassandraMappingContext}.
|
||||||
@@ -197,75 +184,6 @@ public class CassandraMappingContextUnitTests {
|
|||||||
assertThat(lastname.getColumnName().toString()).isEqualTo("mylastname");
|
assertThat(lastname.getColumnName().toString()).isEqualTo("mylastname");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-340
|
|
||||||
public void createdTableSpecificationShouldConsiderClusterColumnOrdering() {
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = mappingContext
|
|
||||||
.getRequiredPersistentEntity(EntityWithOrderedClusteredColumns.class);
|
|
||||||
|
|
||||||
CreateTableSpecification tableSpecification = mappingContext.getCreateTableSpecificationFor(persistentEntity);
|
|
||||||
|
|
||||||
assertThat(tableSpecification.getPartitionKeyColumns()).hasSize(1);
|
|
||||||
assertThat(tableSpecification.getClusteredKeyColumns()).hasSize(3);
|
|
||||||
|
|
||||||
ColumnSpecification breed = tableSpecification.getClusteredKeyColumns().get(0);
|
|
||||||
assertThat(breed.getName().toString()).isEqualTo("breed");
|
|
||||||
assertThat(breed.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
|
||||||
|
|
||||||
ColumnSpecification color = tableSpecification.getClusteredKeyColumns().get(1);
|
|
||||||
assertThat(color.getName().toString()).isEqualTo("color");
|
|
||||||
assertThat(color.getOrdering()).isEqualTo(Ordering.DESCENDING);
|
|
||||||
|
|
||||||
ColumnSpecification kind = tableSpecification.getClusteredKeyColumns().get(2);
|
|
||||||
assertThat(kind.getName().toString()).isEqualTo("kind");
|
|
||||||
assertThat(kind.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-340
|
|
||||||
public void createdTableSpecificationShouldConsiderPrimaryKeyClassClusterColumnOrdering() {
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = mappingContext
|
|
||||||
.getRequiredPersistentEntity(EntityWithPrimaryKeyWithOrderedClusteredColumns.class);
|
|
||||||
|
|
||||||
CreateTableSpecification tableSpecification = mappingContext.getCreateTableSpecificationFor(persistentEntity);
|
|
||||||
|
|
||||||
assertThat(tableSpecification.getPartitionKeyColumns()).hasSize(1);
|
|
||||||
assertThat(tableSpecification.getClusteredKeyColumns()).hasSize(3);
|
|
||||||
|
|
||||||
ColumnSpecification breed = tableSpecification.getClusteredKeyColumns().get(0);
|
|
||||||
assertThat(breed.getName().toString()).isEqualTo("breed");
|
|
||||||
assertThat(breed.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
|
||||||
|
|
||||||
ColumnSpecification color = tableSpecification.getClusteredKeyColumns().get(1);
|
|
||||||
assertThat(color.getName().toString()).isEqualTo("color");
|
|
||||||
assertThat(color.getOrdering()).isEqualTo(Ordering.DESCENDING);
|
|
||||||
|
|
||||||
ColumnSpecification kind = tableSpecification.getClusteredKeyColumns().get(2);
|
|
||||||
assertThat(kind.getName().toString()).isEqualTo("kind");
|
|
||||||
assertThat(kind.getOrdering()).isEqualTo(Ordering.ASCENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-487
|
|
||||||
public void shouldCreateTableForMappedAndConvertedColumn() {
|
|
||||||
|
|
||||||
UserDefinedType mappedudt = UserDefinedTypeBuilder.forName("mappedudt").withField("foo", DataTypes.ASCII).build();
|
|
||||||
|
|
||||||
this.mappingContext.setUserTypeResolver(typeName -> mappedudt);
|
|
||||||
this.mappingContext.setCustomConversions(
|
|
||||||
new CassandraCustomConversions(Collections.singletonList(HumanToStringConverter.INSTANCE)));
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = this.mappingContext
|
|
||||||
.getRequiredPersistentEntity(WithMapOfMixedTypes.class);
|
|
||||||
|
|
||||||
CreateTableSpecification tableSpecification = this.mappingContext.getCreateTableSpecificationFor(persistentEntity);
|
|
||||||
|
|
||||||
assertThat(tableSpecification.getColumns()).hasSize(2);
|
|
||||||
|
|
||||||
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
|
||||||
|
|
||||||
assertThat(column.getType().asCql(true, true)).isEqualTo("map<frozen<mappedudt>, list<text>>");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
private static class PrimaryKeyOnPropertyWithPrimaryKeyClass {
|
private static class PrimaryKeyOnPropertyWithPrimaryKeyClass {
|
||||||
|
|
||||||
@@ -330,82 +248,6 @@ public class CassandraMappingContextUnitTests {
|
|||||||
@PrimaryKey PrimaryKeyWithOrderedClusteredColumns key;
|
@PrimaryKey PrimaryKeyWithOrderedClusteredColumns key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-213
|
|
||||||
public void createIndexShouldConsiderAnnotatedProperties() {
|
|
||||||
|
|
||||||
List<CreateIndexSpecification> specifications = mappingContext
|
|
||||||
.getCreateIndexSpecificationsFor(mappingContext.getRequiredPersistentEntity(IndexedType.class));
|
|
||||||
|
|
||||||
CreateIndexSpecification firstname = getSpecificationFor("first_name", specifications);
|
|
||||||
|
|
||||||
assertThat(firstname.getColumnName()).isEqualTo(CqlIdentifier.fromCql("first_name"));
|
|
||||||
assertThat(firstname.getTableName()).isEqualTo(CqlIdentifier.fromCql("indexedtype"));
|
|
||||||
assertThat(firstname.getName()).isEqualTo(CqlIdentifier.fromCql("my_index"));
|
|
||||||
assertThat(firstname.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
|
||||||
|
|
||||||
CreateIndexSpecification phoneNumbers = getSpecificationFor("phoneNumbers", specifications);
|
|
||||||
|
|
||||||
assertThat(phoneNumbers.getColumnName()).isEqualTo(CqlIdentifier.fromCql("phoneNumbers"));
|
|
||||||
assertThat(phoneNumbers.getTableName()).isEqualTo(CqlIdentifier.fromCql("indexedtype"));
|
|
||||||
assertThat(phoneNumbers.getName()).isNull();
|
|
||||||
assertThat(phoneNumbers.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-213
|
|
||||||
public void createIndexForClusteredPrimaryKeyShouldConsiderAnnotatedAccessors() {
|
|
||||||
|
|
||||||
List<CreateIndexSpecification> specifications = mappingContext
|
|
||||||
.getCreateIndexSpecificationsFor(mappingContext.getRequiredPersistentEntity(CompositeKeyEntity.class));
|
|
||||||
|
|
||||||
CreateIndexSpecification entries = getSpecificationFor("last_name", specifications);
|
|
||||||
|
|
||||||
assertThat(entries.getColumnName()).isEqualTo(CqlIdentifier.fromCql("last_name"));
|
|
||||||
assertThat(entries.getTableName()).isEqualTo(CqlIdentifier.fromCql("compositekeyentity"));
|
|
||||||
assertThat(entries.getName()).isEqualTo(CqlIdentifier.fromCql("my_index"));
|
|
||||||
assertThat(entries.getColumnFunction()).isEqualTo(ColumnFunction.NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-284, DATACASS-651
|
|
||||||
public void shouldRejectUntypedTuples() {
|
|
||||||
|
|
||||||
assertThatThrownBy(() -> this.mappingContext
|
|
||||||
.getCreateTableSpecificationFor(this.mappingContext.getRequiredPersistentEntity(UntypedTupleEntity.class)))
|
|
||||||
.isInstanceOf(MappingException.class);
|
|
||||||
|
|
||||||
assertThatThrownBy(() -> this.mappingContext
|
|
||||||
.getCreateTableSpecificationFor(this.mappingContext.getRequiredPersistentEntity(UntypedTupleMapEntity.class)))
|
|
||||||
.isInstanceOf(MappingException.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-284
|
|
||||||
public void shouldCreateTableForTypedTupleType() {
|
|
||||||
|
|
||||||
CreateTableSpecification tableSpecification = this.mappingContext
|
|
||||||
.getCreateTableSpecificationFor(this.mappingContext.getRequiredPersistentEntity(TypedTupleEntity.class));
|
|
||||||
|
|
||||||
assertThat(tableSpecification.getColumns()).hasSize(2);
|
|
||||||
|
|
||||||
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
|
||||||
|
|
||||||
assertThat(column.getType()).isInstanceOf(TupleType.class);
|
|
||||||
assertThat(column.getType()).isEqualTo(new DefaultTupleType(Arrays.asList(DataTypes.TEXT, DataTypes.BIGINT)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-651
|
|
||||||
public void shouldCreateTableForEntityWithMapOfTuples() {
|
|
||||||
|
|
||||||
CreateTableSpecification tableSpecification = this.mappingContext
|
|
||||||
.getCreateTableSpecificationFor(this.mappingContext.getRequiredPersistentEntity(EntityWithMapOfTuples.class));
|
|
||||||
|
|
||||||
assertThat(tableSpecification.getColumns()).hasSize(2);
|
|
||||||
|
|
||||||
ColumnSpecification column = tableSpecification.getColumns().get(1);
|
|
||||||
|
|
||||||
assertThat(column.getType()).isInstanceOf(MapType.class);
|
|
||||||
assertThat(column.getType())
|
|
||||||
.isEqualTo(DataTypes.mapOf(DataTypes.TEXT, new DefaultTupleType(Arrays.asList(DataTypes.TEXT))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CreateIndexSpecification getSpecificationFor(String column,
|
private static CreateIndexSpecification getSpecificationFor(String column,
|
||||||
List<CreateIndexSpecification> specifications) {
|
List<CreateIndexSpecification> specifications) {
|
||||||
|
|
||||||
@@ -453,46 +295,6 @@ public class CassandraMappingContextUnitTests {
|
|||||||
assertThat(mappingContext.shouldCreatePersistentEntityFor(ClassTypeInformation.from(Human.class))).isFalse();
|
assertThat(mappingContext.shouldCreatePersistentEntityFor(ClassTypeInformation.from(Human.class))).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-349
|
|
||||||
public void propertyTypeShouldConsiderRegisteredConverterForPropertyType() {
|
|
||||||
|
|
||||||
mappingContext.setCustomConversions(
|
|
||||||
new CassandraCustomConversions(Collections.singletonList(StringMapToStringConverter.INSTANCE)));
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = mappingContext
|
|
||||||
.getRequiredPersistentEntity(TypeWithCustomConvertedMap.class);
|
|
||||||
|
|
||||||
assertThat(mappingContext.getDataType(persistentEntity.getRequiredPersistentProperty("stringMap")))
|
|
||||||
.isEqualTo(DataTypes.TEXT);
|
|
||||||
|
|
||||||
assertThat(mappingContext.getDataType(persistentEntity.getRequiredPersistentProperty("blobMap")))
|
|
||||||
.isEqualTo(DataTypes.ASCII);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-349
|
|
||||||
public void propertyTypeShouldConsiderRegisteredConverterForCollectionComponentType() {
|
|
||||||
|
|
||||||
mappingContext.setCustomConversions(
|
|
||||||
new CassandraCustomConversions(Collections.singletonList(HumanToStringConverter.INSTANCE)));
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = mappingContext
|
|
||||||
.getRequiredPersistentEntity(TypeWithListOfHumans.class);
|
|
||||||
|
|
||||||
assertThat(mappingContext.getDataType(persistentEntity.getRequiredPersistentProperty("humans")))
|
|
||||||
.isEqualTo(DataTypes.listOf(DataTypes.TEXT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-302
|
|
||||||
public void propertyTypeShouldMapToTime() {
|
|
||||||
|
|
||||||
CassandraPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(AllPossibleTypes.class);
|
|
||||||
|
|
||||||
assertThat(mappingContext.getDataType(persistentEntity.getRequiredPersistentProperty("time")))
|
|
||||||
.isEqualTo(DataTypes.TIME);
|
|
||||||
assertThat(mappingContext.getDataType(persistentEntity.getRequiredPersistentProperty("jodaLocalTime")))
|
|
||||||
.isEqualTo(DataTypes.TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-172, DATACASS-455
|
@Test // DATACASS-172, DATACASS-455
|
||||||
public void shouldRegisterUdtTypes() {
|
public void shouldRegisterUdtTypes() {
|
||||||
|
|
||||||
@@ -566,45 +368,6 @@ public class CassandraMappingContextUnitTests {
|
|||||||
assertThat(mappingContext.usesUserType(CqlIdentifier.fromCql("mappedudt"))).isTrue();
|
assertThat(mappingContext.usesUserType(CqlIdentifier.fromCql("mappedudt"))).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-506
|
|
||||||
public void shouldCreatedUserTypeSpecificationsWithAnnotatedTypeName() {
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
mappingContext.getCreateUserTypeSpecificationFor(mappingContext.getRequiredPersistentEntity(WithUdt.class)))
|
|
||||||
.isNotNull();
|
|
||||||
assertThat(
|
|
||||||
mappingContext.getCreateUserTypeSpecificationFor(mappingContext.getRequiredPersistentEntity(Nested.class)))
|
|
||||||
.isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-172
|
|
||||||
public void createTableForComplexPrimaryKeyShouldFail() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
mappingContext.getCreateTableSpecificationFor(
|
|
||||||
mappingContext.getRequiredPersistentEntity(EntityWithComplexPrimaryKeyColumn.class));
|
|
||||||
fail("Missing MappingException");
|
|
||||||
} catch (MappingException e) {
|
|
||||||
assertThat(e).hasMessageContaining("Unknown type [class java.lang.Object] for property [complexObject]");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mappingContext
|
|
||||||
.getCreateTableSpecificationFor(mappingContext.getRequiredPersistentEntity(EntityWithComplexId.class));
|
|
||||||
fail("Missing MappingException");
|
|
||||||
} catch (MappingException e) {
|
|
||||||
assertThat(e).hasMessageContaining("Unknown type [class java.lang.Object] for property [complexObject]");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mappingContext.getCreateTableSpecificationFor(
|
|
||||||
mappingContext.getRequiredPersistentEntity(EntityWithPrimaryKeyClassWithComplexId.class));
|
|
||||||
fail("Missing MappingException");
|
|
||||||
} catch (MappingException e) {
|
|
||||||
assertThat(e).hasMessageContaining("Unknown type [class java.lang.Object] for property [complexObject]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // DATACASS-282, DATACASS-455
|
@Test // DATACASS-282, DATACASS-455
|
||||||
public void shouldNotRetainInvalidEntitiesInCache() {
|
public void shouldNotRetainInvalidEntitiesInCache() {
|
||||||
|
|
||||||
@@ -632,26 +395,11 @@ public class CassandraMappingContextUnitTests {
|
|||||||
@PrimaryKeyColumn String bar;
|
@PrimaryKeyColumn String bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
|
||||||
static class EntityWithComplexPrimaryKeyColumn {
|
|
||||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) Object complexObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Table
|
|
||||||
static class EntityWithComplexId {
|
|
||||||
@Id Object complexObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PrimaryKeyClass
|
@PrimaryKeyClass
|
||||||
static class PrimaryKeyClassWithComplexId {
|
static class PrimaryKeyClassWithComplexId {
|
||||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) Object complexObject;
|
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) Object complexObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
|
||||||
static class EntityWithPrimaryKeyClassWithComplexId {
|
|
||||||
@Id PrimaryKeyClassWithComplexId primaryKeyClassWithComplexId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Human {}
|
private static class Human {}
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
@@ -679,12 +427,6 @@ public class CassandraMappingContextUnitTests {
|
|||||||
@CassandraType(type = Name.UDT, userTypeName = "NestedType") Nested nested;
|
@CassandraType(type = Name.UDT, userTypeName = "NestedType") Nested nested;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
|
||||||
private static class WithMapOfMixedTypes {
|
|
||||||
@Id String id;
|
|
||||||
Map<MappedUdt, List<Human>> people;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum HumanToStringConverter implements Converter<Human, String> {
|
enum HumanToStringConverter implements Converter<Human, String> {
|
||||||
|
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
@@ -695,63 +437,14 @@ public class CassandraMappingContextUnitTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
|
||||||
private static class TypeWithCustomConvertedMap {
|
|
||||||
@Id String id;
|
|
||||||
Map<String, Collection<String>> stringMap;
|
|
||||||
@CassandraType(type = Name.ASCII) Map<String, Collection<String>> blobMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Table
|
|
||||||
private static class TypeWithListOfHumans {
|
|
||||||
@Id String id;
|
|
||||||
List<Human> humans;
|
|
||||||
}
|
|
||||||
|
|
||||||
@WritingConverter
|
|
||||||
enum StringMapToStringConverter implements Converter<Map<String, Collection<String>>, String> {
|
|
||||||
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String convert(Map<String, Collection<String>> source) {
|
|
||||||
return "serialized";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@org.springframework.data.cassandra.core.mapping.UserDefinedType(value = "NestedType")
|
@org.springframework.data.cassandra.core.mapping.UserDefinedType(value = "NestedType")
|
||||||
public static class Nested {
|
public static class Nested {
|
||||||
String s1;
|
String s1;
|
||||||
@CassandraType(type = Name.UDT,
|
@CassandraType(type = Name.UDT, userTypeName = "AnotherNestedType") AnotherNested anotherNested;
|
||||||
userTypeName = "AnotherNestedType") AnotherNested anotherNested;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@org.springframework.data.cassandra.core.mapping.UserDefinedType(value = "AnotherNestedType")
|
@org.springframework.data.cassandra.core.mapping.UserDefinedType(value = "AnotherNestedType")
|
||||||
public static class AnotherNested {
|
public static class AnotherNested {
|
||||||
String str;
|
String str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Table
|
|
||||||
static class TypedTupleEntity {
|
|
||||||
@Id String id;
|
|
||||||
@CassandraType(type = Name.TUPLE, typeArguments = { Name.VARCHAR, Name.BIGINT }) TupleValue typed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Table
|
|
||||||
static class EntityWithMapOfTuples {
|
|
||||||
@Id String id;
|
|
||||||
Map<String, MappedTuple> map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Table
|
|
||||||
static class UntypedTupleEntity {
|
|
||||||
@Id String id;
|
|
||||||
TupleValue untyped;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Table
|
|
||||||
static class UntypedTupleMapEntity {
|
|
||||||
@Id String id;
|
|
||||||
Map<String, TupleValue> untyped;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import java.lang.annotation.Target;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import org.springframework.core.annotation.AliasFor;
|
import org.springframework.core.annotation.AliasFor;
|
||||||
@@ -40,8 +39,6 @@ import com.datastax.oss.driver.api.core.CqlIdentifier;
|
|||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class CassandraUserTypePersistentEntityUnitTests {
|
public class CassandraUserTypePersistentEntityUnitTests {
|
||||||
|
|
||||||
@Mock UserTypeResolver userTypeResolverMock;
|
|
||||||
|
|
||||||
@Test // DATACASS-172
|
@Test // DATACASS-172
|
||||||
public void isUserDefinedTypeShouldReportTrue() {
|
public void isUserDefinedTypeShouldReportTrue() {
|
||||||
|
|
||||||
@@ -83,7 +80,7 @@ public class CassandraUserTypePersistentEntityUnitTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private <T> CassandraUserTypePersistentEntity<T> getEntity(Class<T> entityClass) {
|
private <T> CassandraUserTypePersistentEntity<T> getEntity(Class<T> entityClass) {
|
||||||
return new CassandraUserTypePersistentEntity<>(ClassTypeInformation.from(entityClass), null, userTypeResolverMock);
|
return new CassandraUserTypePersistentEntity<>(ClassTypeInformation.from(entityClass), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UserDefinedType
|
@UserDefinedType
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentProper
|
|||||||
import org.springframework.data.cassandra.repository.query.ConvertingParameterAccessor.PotentiallyConvertingIterator;
|
import org.springframework.data.cassandra.repository.query.ConvertingParameterAccessor.PotentiallyConvertingIterator;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
import com.datastax.oss.driver.api.core.type.DataTypes;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link ConvertingParameterAccessor}.
|
* Unit tests for {@link ConvertingParameterAccessor}.
|
||||||
@@ -56,15 +55,13 @@ public class ConvertingParameterAccessorUnitTests {
|
|||||||
|
|
||||||
this.converter = new MappingCassandraConverter();
|
this.converter = new MappingCassandraConverter();
|
||||||
this.converter.afterPropertiesSet();
|
this.converter.afterPropertiesSet();
|
||||||
this.convertingParameterAccessor = new ConvertingParameterAccessor(converter, mockParameterAccessor,
|
this.convertingParameterAccessor = new ConvertingParameterAccessor(converter, mockParameterAccessor);
|
||||||
CodecRegistry.DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATACASS-296
|
@Test // DATACASS-296
|
||||||
public void shouldReturnNullBindableValue() {
|
public void shouldReturnNullBindableValue() {
|
||||||
|
|
||||||
ConvertingParameterAccessor accessor = new ConvertingParameterAccessor(converter, mockParameterAccessor,
|
ConvertingParameterAccessor accessor = new ConvertingParameterAccessor(converter, mockParameterAccessor);
|
||||||
CodecRegistry.DEFAULT);
|
|
||||||
|
|
||||||
assertThat(accessor.getBindableValue(0)).isNull();
|
assertThat(accessor.getBindableValue(0)).isNull();
|
||||||
}
|
}
|
||||||
@@ -75,8 +72,7 @@ public class ConvertingParameterAccessorUnitTests {
|
|||||||
|
|
||||||
when(mockParameterAccessor.getBindableValue(0)).thenReturn("hello");
|
when(mockParameterAccessor.getBindableValue(0)).thenReturn("hello");
|
||||||
|
|
||||||
ConvertingParameterAccessor accessor = new ConvertingParameterAccessor(converter, mockParameterAccessor,
|
ConvertingParameterAccessor accessor = new ConvertingParameterAccessor(converter, mockParameterAccessor);
|
||||||
CodecRegistry.DEFAULT);
|
|
||||||
|
|
||||||
assertThat(accessor.getBindableValue(0)).isEqualTo((Object) "hello");
|
assertThat(accessor.getBindableValue(0)).isEqualTo((Object) "hello");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ public class PartTreeCassandraQueryUnitTests {
|
|||||||
args);
|
args);
|
||||||
|
|
||||||
return partTreeQuery.createQuery(
|
return partTreeQuery.createQuery(
|
||||||
new ConvertingParameterAccessor(mockCassandraOperations.getConverter(), accessor, CodecRegistry.DEFAULT));
|
new ConvertingParameterAccessor(mockCassandraOperations.getConverter(), accessor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PartTreeCassandraQuery createQueryForMethod(Class<?> repositoryInterface, String methodName,
|
private PartTreeCassandraQuery createQueryForMethod(Class<?> repositoryInterface, String methodName,
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import org.springframework.util.ClassUtils;
|
|||||||
|
|
||||||
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
|
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
|
||||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link ReactivePartTreeCassandraQuery}.
|
* Unit tests for {@link ReactivePartTreeCassandraQuery}.
|
||||||
@@ -177,8 +176,7 @@ public class ReactivePartTreeCassandraQueryUnitTests {
|
|||||||
CassandraParameterAccessor accessor = new CassandraParametersParameterAccessor(partTreeQuery.getQueryMethod(),
|
CassandraParameterAccessor accessor = new CassandraParametersParameterAccessor(partTreeQuery.getQueryMethod(),
|
||||||
args);
|
args);
|
||||||
|
|
||||||
return partTreeQuery.createQuery(new ConvertingParameterAccessor(mockCassandraOperations.getConverter(), accessor,
|
return partTreeQuery.createQuery(new ConvertingParameterAccessor(mockCassandraOperations.getConverter(), accessor));
|
||||||
CodecRegistry.DEFAULT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReactivePartTreeCassandraQuery createQueryForMethod(Class<?> repositoryInterface, String methodName,
|
private ReactivePartTreeCassandraQuery createQueryForMethod(Class<?> repositoryInterface, String methodName,
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
|||||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||||
import com.datastax.oss.driver.api.core.type.DataTypes;
|
import com.datastax.oss.driver.api.core.type.DataTypes;
|
||||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link StringBasedCassandraQuery}.
|
* Unit tests for {@link StringBasedCassandraQuery}.
|
||||||
@@ -327,8 +326,7 @@ public class StringBasedCassandraQueryUnitTests {
|
|||||||
|
|
||||||
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByCreatedDate", LocalDate.class);
|
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByCreatedDate", LocalDate.class);
|
||||||
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
|
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
|
||||||
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), LocalDate.of(2010, 7, 4)),
|
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), LocalDate.of(2010, 7, 4)));
|
||||||
CodecRegistry.DEFAULT);
|
|
||||||
|
|
||||||
SimpleStatement actual = cassandraQuery.createQuery(accessor);
|
SimpleStatement actual = cassandraQuery.createQuery(accessor);
|
||||||
|
|
||||||
@@ -347,8 +345,7 @@ public class StringBasedCassandraQueryUnitTests {
|
|||||||
|
|
||||||
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByMainAddress", AddressType.class);
|
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByMainAddress", AddressType.class);
|
||||||
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
|
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
|
||||||
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), new AddressType()),
|
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), new AddressType()));
|
||||||
CodecRegistry.DEFAULT);
|
|
||||||
|
|
||||||
SimpleStatement actual = cassandraQuery.createQuery(accessor);
|
SimpleStatement actual = cassandraQuery.createQuery(accessor);
|
||||||
|
|
||||||
@@ -360,8 +357,13 @@ public class StringBasedCassandraQueryUnitTests {
|
|||||||
public void bindsUdtValuePropertyCorrectly() throws Exception {
|
public void bindsUdtValuePropertyCorrectly() throws Exception {
|
||||||
|
|
||||||
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByMainAddress", UdtValue.class);
|
StringBasedCassandraQuery cassandraQuery = getQueryMethod("findByMainAddress", UdtValue.class);
|
||||||
|
|
||||||
|
UserDefinedType addressType = UserDefinedTypeBuilder.forName("address").withField("city", DataTypes.TEXT)
|
||||||
|
.withField("country", DataTypes.TEXT).build();
|
||||||
|
when(udtValue.getType()).thenReturn(addressType);
|
||||||
|
|
||||||
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
|
CassandraParameterAccessor accessor = new ConvertingParameterAccessor(converter,
|
||||||
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), udtValue), CodecRegistry.DEFAULT);
|
new CassandraParametersParameterAccessor(cassandraQuery.getQueryMethod(), udtValue));
|
||||||
|
|
||||||
SimpleStatement actual = cassandraQuery.createQuery(accessor);
|
SimpleStatement actual = cassandraQuery.createQuery(accessor);
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ class StubParameterAccessor implements CassandraParameterAccessor {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static ConvertingParameterAccessor getAccessor(CassandraConverter converter, Object... parameters) {
|
public static ConvertingParameterAccessor getAccessor(CassandraConverter converter, Object... parameters) {
|
||||||
return new ConvertingParameterAccessor(converter, new StubParameterAccessor(parameters),
|
return new ConvertingParameterAccessor(converter, new StubParameterAccessor(parameters));
|
||||||
CodecRegistry.DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.repository.support;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||||
|
import org.springframework.data.cassandra.core.convert.SchemaFactory;
|
||||||
import org.springframework.data.cassandra.core.cql.SessionCallback;
|
import org.springframework.data.cassandra.core.cql.SessionCallback;
|
||||||
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
|
||||||
@@ -44,6 +45,7 @@ public class SchemaTestUtils {
|
|||||||
|
|
||||||
CassandraMappingContext mappingContext = operations.getConverter().getMappingContext();
|
CassandraMappingContext mappingContext = operations.getConverter().getMappingContext();
|
||||||
CassandraPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entityClass);
|
CassandraPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(entityClass);
|
||||||
|
SchemaFactory schemaFactory = new SchemaFactory(operations.getConverter());
|
||||||
|
|
||||||
operations.getCqlOperations().execute((SessionCallback<Object>) session -> {
|
operations.getCqlOperations().execute((SessionCallback<Object>) session -> {
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ public class SchemaTestUtils {
|
|||||||
.flatMap(it -> it.getTable(persistentEntity.getTableName()));
|
.flatMap(it -> it.getTable(persistentEntity.getTableName()));
|
||||||
|
|
||||||
if (!table.isPresent()) {
|
if (!table.isPresent()) {
|
||||||
CreateTableSpecification tableSpecification = mappingContext.getCreateTableSpecificationFor(persistentEntity);
|
CreateTableSpecification tableSpecification = schemaFactory.getCreateTableSpecificationFor(persistentEntity);
|
||||||
operations.getCqlOperations().execute(new CreateTableCqlGenerator(tableSpecification).toCql());
|
operations.getCqlOperations().execute(new CreateTableCqlGenerator(tableSpecification).toCql());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ Paging state now uses `ByteBuffer`.
|
|||||||
* Introduction of `StatementBuilder` to functionally build statements as the QueryBuilder API uses immutable statement types.
|
* Introduction of `StatementBuilder` to functionally build statements as the QueryBuilder API uses immutable statement types.
|
||||||
* `Session` bean renamed from `session` to `cassandraSession` and `SessionFactory` bean renamed from `sessionFactory` to `cassandraSessionFactory`.
|
* `Session` bean renamed from `session` to `cassandraSession` and `SessionFactory` bean renamed from `sessionFactory` to `cassandraSessionFactory`.
|
||||||
* `ReactiveSession` bean renamed from `reactiveSession` to `reactiveCassandraSession` and `ReactiveSessionFactory` bean renamed from `reactiveSessionFactory` to `reactiveCassandraSessionFactory`.
|
* `ReactiveSession` bean renamed from `reactiveSession` to `reactiveCassandraSession` and `ReactiveSessionFactory` bean renamed from `reactiveSessionFactory` to `reactiveCassandraSessionFactory`.
|
||||||
|
* Data type resolution was moved into `ColumnTypeResolver` so all `DataType`-related methods were moved from `CassandraPersistentEntity`/`CassandraPersistentProperty` into `ColumnTypeResolver` (affected methods are `MappingContext.getDataType(…)`, `CassandraPersistentProperty.getDataType()`, `CassandraPersistentEntity.getUserType()`, and `CassandraPersistentEntity.getTupleType()`).
|
||||||
|
* Schema creation was moved from `MappingContext` to `SchemaFactory` (affected methods are `CassandraMappingContext.getCreateTableSpecificationFor(…)`, `CassandraMappingContext.getCreateIndexSpecificationsFor(…)`, and `CassandraMappingContext.getCreateUserTypeSpecificationFor(…)`).
|
||||||
|
|
||||||
== Deprecations
|
== Deprecations
|
||||||
|
|
||||||
@@ -151,6 +153,8 @@ Paging state now uses `ByteBuffer`.
|
|||||||
* Spring Data's `CqlIdentifier`, use the driver `CqlIdentifier` instead.
|
* Spring Data's `CqlIdentifier`, use the driver `CqlIdentifier` instead.
|
||||||
* `forceQuote` attributes as quoting is no longer required. `CqlIdentifier` properly escapes reserved keywords and takes care of case-sensitivity.
|
* `forceQuote` attributes as quoting is no longer required. `CqlIdentifier` properly escapes reserved keywords and takes care of case-sensitivity.
|
||||||
* `fetchSize` on `QueryOptions` and `…CqlTemplate` types was deprecated, use `pageSize` instead
|
* `fetchSize` on `QueryOptions` and `…CqlTemplate` types was deprecated, use `pageSize` instead
|
||||||
|
* `CassandraMappingContext.setUserTypeResolver(…)`, `CassandraMappingContext.setCodecRegistry(…)`, and `CassandraMappingContext.setCustomConversions(…)`: Configure these properties on `CassandraConverter`.
|
||||||
|
* `TupleTypeFactory` and `CassandraMappingContext.setTupleTypeFactory(…)`: `TupleTypeFactory` is no longer used as the Cassandra driver ships with a `DataTypes.tupleOf(…)` factory method.
|
||||||
* Schema creation via `CqlSessionFactoryBean` (`cassandra:session`) is deprecated.
|
* Schema creation via `CqlSessionFactoryBean` (`cassandra:session`) is deprecated.
|
||||||
Keyspace creation via `CqlSessionFactoryBean` (`cassandra:session`) is not affected.
|
Keyspace creation via `CqlSessionFactoryBean` (`cassandra:session`) is not affected.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user