DATACASS-33 - refactored a bunch & ready to begin testing compound primary key support
This commit is contained in:
@@ -21,6 +21,14 @@ import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.cassandra.core.keyspace.AlterKeyspaceSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.AlterTableSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateIndexSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateTableSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropIndexSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropKeyspaceSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropTableSpecification;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
@@ -754,4 +762,59 @@ public interface CqlOperations {
|
||||
*/
|
||||
void truncate(String tableName);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(DropTableSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(CreateTableSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(AlterTableSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(DropKeyspaceSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(CreateKeyspaceSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(AlterKeyspaceSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(DropIndexSpecification specification);
|
||||
|
||||
/**
|
||||
* Convenience method to convert the given specification to CQL and execute it.
|
||||
*
|
||||
* @param specification The specification to execute; must not be null.
|
||||
*/
|
||||
ResultSet execute(CreateIndexSpecification specification);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,22 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.springframework.cassandra.core.cql.generator.AlterKeyspaceCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.AlterTableCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.CreateIndexCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.CreateKeyspaceCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.DropIndexCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.DropKeyspaceCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.DropTableCqlGenerator;
|
||||
import org.springframework.cassandra.core.keyspace.AlterKeyspaceSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.AlterTableSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateIndexSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateTableSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropIndexSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropKeyspaceSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropTableSpecification;
|
||||
import org.springframework.cassandra.support.CassandraAccessor;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.QueryTimeoutException;
|
||||
@@ -278,6 +294,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
process(doExecute(cql, options), rch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void query(String cql, RowCallbackHandler rch) throws DataAccessException {
|
||||
query(cql, rch, null);
|
||||
}
|
||||
@@ -287,26 +304,32 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
return process(doExecute(cql, options), rowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String cql, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(cql, rowMapper, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> queryForListOfMap(String cql) throws DataAccessException {
|
||||
return processListOfMap(doExecute(cql, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryForList(String cql, Class<T> elementType) throws DataAccessException {
|
||||
return processList(doExecute(cql, null), elementType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryForMap(String cql) throws DataAccessException {
|
||||
return processMap(doExecute(cql, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(String cql, Class<T> requiredType) throws DataAccessException {
|
||||
return processOne(doExecute(cql, null), requiredType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(String cql, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return processOne(doExecute(cql, null), rowMapper);
|
||||
}
|
||||
@@ -766,6 +789,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Executing prepared CQL query");
|
||||
|
||||
return execute(psc, new PreparedStatementCallback<T>() {
|
||||
@Override
|
||||
public T doInPreparedStatement(PreparedStatement ps) throws DriverException {
|
||||
ResultSet rs = null;
|
||||
BoundStatement bs = null;
|
||||
@@ -794,6 +818,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Executing prepared CQL query");
|
||||
|
||||
execute(psc, new PreparedStatementCallback<Object>() {
|
||||
@Override
|
||||
public Object doInPreparedStatement(PreparedStatement ps) throws DriverException {
|
||||
ResultSet rs = null;
|
||||
BoundStatement bs = null;
|
||||
@@ -822,6 +847,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Executing prepared CQL query");
|
||||
|
||||
return execute(psc, new PreparedStatementCallback<List<T>>() {
|
||||
@Override
|
||||
public List<T> doInPreparedStatement(PreparedStatement ps) throws DriverException {
|
||||
ResultSet rs = null;
|
||||
BoundStatement bs = null;
|
||||
@@ -843,4 +869,100 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
return query(psc, psb, rowMapper, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final DropTableSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(DropTableCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final CreateTableSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(CreateTableCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final AlterTableSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(AlterTableCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final DropKeyspaceSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(DropKeyspaceCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final CreateKeyspaceSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(CreateKeyspaceCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final AlterKeyspaceSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(AlterKeyspaceCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final DropIndexSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(DropIndexCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet execute(final CreateIndexSpecification specification) {
|
||||
|
||||
return execute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) throws DataAccessException {
|
||||
return s.execute(CreateIndexCqlGenerator.toCql(specification));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,8 @@ package org.springframework.cassandra.core.cql;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
public class CqlStringUtils {
|
||||
|
||||
protected static final String SINGLE_QUOTE = "\'";
|
||||
@@ -24,6 +26,8 @@ public class CqlStringUtils {
|
||||
protected static final String DOUBLE_QUOTE = "\"";
|
||||
protected static final String DOUBLE_DOUBLE_QUOTE = "\"\"";
|
||||
protected static final String EMPTY_STRING = "";
|
||||
protected static final String TYPE_PARAMETER_PREFIX = "<";
|
||||
protected static final String TYPE_PARAMETER_SUFFIX = ">";
|
||||
|
||||
public static StringBuilder noNull(StringBuilder sb) {
|
||||
return sb == null ? new StringBuilder() : sb;
|
||||
@@ -137,4 +141,34 @@ public class CqlStringUtils {
|
||||
public static String removeSingleQuotes(Object thing) {
|
||||
return thing == null ? (String) null : ((String) thing).replaceAll(SINGLE_QUOTE, EMPTY_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the given {@link DataType} as a CQL string.
|
||||
*
|
||||
* @param dataType The {@link DataType} to render; must not be null.
|
||||
*/
|
||||
public static String toCql(DataType dataType) {
|
||||
|
||||
if (dataType.getTypeArguments().isEmpty()) {
|
||||
return dataType.getName().name();
|
||||
}
|
||||
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(dataType.getName().name()).append(TYPE_PARAMETER_PREFIX);
|
||||
|
||||
boolean first = true;
|
||||
|
||||
for (DataType argDataType : dataType.getTypeArguments()) {
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
s.append(',');
|
||||
}
|
||||
|
||||
s.append(argDataType.getName().name());
|
||||
}
|
||||
|
||||
return s.append(TYPE_PARAMETER_SUFFIX).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,15 @@ import org.springframework.cassandra.core.keyspace.Option;
|
||||
*/
|
||||
public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator<AlterKeyspaceSpecification> {
|
||||
|
||||
public static String toCql(AlterKeyspaceSpecification specification) {
|
||||
return new AlterKeyspaceCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public AlterKeyspaceCqlGenerator(AlterKeyspaceSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
cql = noNull(cql);
|
||||
|
||||
|
||||
@@ -34,10 +34,15 @@ import org.springframework.cassandra.core.keyspace.TableOption;
|
||||
*/
|
||||
public class AlterTableCqlGenerator extends TableOptionsCqlGenerator<AlterTableSpecification> {
|
||||
|
||||
public static String toCql(AlterTableSpecification specification) {
|
||||
return new AlterTableCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public AlterTableCqlGenerator(AlterTableSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
cql = noNull(cql);
|
||||
|
||||
|
||||
@@ -28,10 +28,15 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class CreateIndexCqlGenerator extends IndexNameCqlGenerator<CreateIndexSpecification> {
|
||||
|
||||
public static String toCql(CreateIndexSpecification specification) {
|
||||
return new CreateIndexCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public CreateIndexCqlGenerator(CreateIndexSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
|
||||
cql = noNull(cql);
|
||||
|
||||
@@ -30,10 +30,15 @@ import org.springframework.cassandra.core.keyspace.Option;
|
||||
*/
|
||||
public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator<CreateKeyspaceSpecification> {
|
||||
|
||||
public static String toCql(CreateKeyspaceSpecification specification) {
|
||||
return new CreateKeyspaceCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public CreateKeyspaceCqlGenerator(CreateKeyspaceSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
|
||||
cql = noNull(cql);
|
||||
|
||||
@@ -35,10 +35,15 @@ import org.springframework.cassandra.core.keyspace.Option;
|
||||
*/
|
||||
public class CreateTableCqlGenerator extends TableCqlGenerator<CreateTableSpecification> {
|
||||
|
||||
public static String toCql(CreateTableSpecification specification) {
|
||||
return new CreateTableCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public CreateTableCqlGenerator(CreateTableSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
|
||||
cql = noNull(cql);
|
||||
|
||||
@@ -27,10 +27,15 @@ import org.springframework.cassandra.core.keyspace.DropIndexSpecification;
|
||||
*/
|
||||
public class DropIndexCqlGenerator extends IndexNameCqlGenerator<DropIndexSpecification> {
|
||||
|
||||
public static String toCql(DropIndexSpecification specification) {
|
||||
return new DropIndexCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public DropIndexCqlGenerator(DropIndexSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
return noNull(cql).append("DROP INDEX ")
|
||||
// .append(spec().getIfExists() ? "IF EXISTS " : "")
|
||||
|
||||
@@ -26,10 +26,15 @@ import org.springframework.cassandra.core.keyspace.DropKeyspaceSpecification;
|
||||
*/
|
||||
public class DropKeyspaceCqlGenerator extends KeyspaceNameCqlGenerator<DropKeyspaceSpecification> {
|
||||
|
||||
public static String toCql(DropKeyspaceSpecification specification) {
|
||||
return new DropKeyspaceCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public DropKeyspaceCqlGenerator(DropKeyspaceSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
return noNull(cql).append("DROP KEYSPACE ").append(spec().getIfExists() ? "IF EXISTS " : "")
|
||||
.append(spec().getNameAsIdentifier()).append(";");
|
||||
|
||||
@@ -26,10 +26,15 @@ import org.springframework.cassandra.core.keyspace.DropTableSpecification;
|
||||
*/
|
||||
public class DropTableCqlGenerator extends TableNameCqlGenerator<DropTableSpecification> {
|
||||
|
||||
public static String toCql(DropTableSpecification specification) {
|
||||
return new DropTableCqlGenerator(specification).toCql();
|
||||
}
|
||||
|
||||
public DropTableCqlGenerator(DropTableSpecification specification) {
|
||||
super(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
return noNull(cql).append("DROP TABLE ")
|
||||
// .append(spec().getIfExists() ? "IF EXISTS " : "")
|
||||
|
||||
@@ -47,6 +47,11 @@ public class CreateTableSpecification extends TableSpecification<CreateTableSpec
|
||||
return ifNotExists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateTableSpecification name(String name) {
|
||||
return (CreateTableSpecification) super.name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point into the {@link CreateTableSpecification}'s fluent API to create a table. Convenient if imported
|
||||
* statically.
|
||||
|
||||
@@ -46,4 +46,15 @@ public class DropTableSpecification extends TableNameSpecification<DropTableSpec
|
||||
public static DropTableSpecification dropTable() {
|
||||
return new DropTableSpecification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point into the {@link DropTableSpecification}'s fluent API to drop a table. Convenient if imported
|
||||
* statically. This static method is shorter than the no-arg form, which would be
|
||||
* <code>dropTable().name(tableName)</code>.
|
||||
*
|
||||
* @param tableName The name of the table to drop.
|
||||
*/
|
||||
public static DropTableSpecification dropTable(String tableName) {
|
||||
return new DropTableSpecification().name(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.datastax.driver.core.Session;
|
||||
|
||||
/**
|
||||
* @author David Webb
|
||||
*
|
||||
*/
|
||||
public class CassandraAccessor implements InitializingBean {
|
||||
|
||||
@@ -56,9 +55,7 @@ public class CassandraAccessor implements InitializingBean {
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getSession() == null) {
|
||||
throw new IllegalArgumentException("Property 'session' is required");
|
||||
}
|
||||
Assert.notNull(session);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,8 @@ import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
|
||||
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.EntityMapping;
|
||||
import org.springframework.data.cassandra.mapping.Mapping;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.config.java;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -27,7 +28,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean;
|
||||
import org.springframework.data.cassandra.config.Mapping;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
|
||||
@@ -35,6 +35,8 @@ import org.springframework.data.cassandra.core.CassandraAdminOperations;
|
||||
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
|
||||
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.Mapping;
|
||||
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -139,6 +141,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
|
||||
false);
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Table.class));
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(PrimaryKeyClass.class));
|
||||
|
||||
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cassandra.config.xml.CassandraSessionParser;
|
||||
import org.springframework.data.cassandra.config.DefaultDataBeanNames;
|
||||
import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean;
|
||||
import org.springframework.data.cassandra.config.EntityMapping;
|
||||
import org.springframework.data.cassandra.config.Mapping;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.mapping.EntityMapping;
|
||||
import org.springframework.data.cassandra.mapping.Mapping;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.springframework.data.cassandra.convert;
|
||||
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
|
||||
public class CassandraPersistentEntityParameterValueProvider extends
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> {
|
||||
|
||||
public CassandraPersistentEntityParameterValueProvider(PersistentEntity<?, CassandraPersistentProperty> entity,
|
||||
PropertyValueProvider<CassandraPersistentProperty> provider, Object parent) {
|
||||
super(entity, provider, parent);
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,6 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.mapping.model.SpELContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -54,14 +52,14 @@ import com.datastax.driver.core.querybuilder.Update;
|
||||
public class MappingCassandraConverter extends AbstractCassandraConverter implements CassandraConverter,
|
||||
ApplicationContextAware, BeanClassLoaderAware {
|
||||
|
||||
protected static final Logger log = LoggerFactory.getLogger(MappingCassandraConverter.class);
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected final CassandraMappingContext mappingContext;
|
||||
protected ApplicationContext applicationContext;
|
||||
private SpELContext spELContext;
|
||||
private boolean useFieldAccessOnly = true;
|
||||
protected SpELContext spELContext;
|
||||
protected boolean useFieldAccessOnly = true;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
protected ClassLoader beanClassLoader;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingCassandraConverter} with the given {@link CassandraMappingContext}.
|
||||
@@ -111,45 +109,48 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
|
||||
|
||||
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(row, spELContext);
|
||||
|
||||
final PropertyValueProvider<CassandraPersistentProperty> propertyProvider = new CassandraPropertyValueProvider(row,
|
||||
evaluator);
|
||||
final CassandraPropertyValueProvider propertyProvider = new CassandraPropertyValueProvider(row, evaluator);
|
||||
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<CassandraPersistentProperty>(
|
||||
CassandraPersistentEntityParameterValueProvider parameterProvider = new CassandraPersistentEntityParameterValueProvider(
|
||||
entity, propertyProvider, null);
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
S instance = instantiator.createInstance(entity, parameterProvider);
|
||||
|
||||
final BeanWrapper<CassandraPersistentEntity<S>, S> wrapper = BeanWrapper.create(instance, conversionService);
|
||||
S result = wrapper.getBean();
|
||||
|
||||
readPropertiesFromRow(entity, row, propertyProvider, wrapper);
|
||||
|
||||
return wrapper.getBean();
|
||||
}
|
||||
|
||||
protected void readPropertiesFromRow(final CassandraPersistentEntity<?> entity, final Row row,
|
||||
final CassandraPropertyValueProvider propertyProvider, final BeanWrapper<?, ?> wrapper) {
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
MappingCassandraConverter.this.handlePersistentPropertyRead(row, entity, prop, propertyProvider, wrapper);
|
||||
MappingCassandraConverter.this.readPropertyFromRow(row, entity, prop, propertyProvider, wrapper);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void handlePersistentPropertyRead(final Row row, final CassandraPersistentEntity<?> entity,
|
||||
final CassandraPersistentProperty prop,
|
||||
final PropertyValueProvider<CassandraPersistentProperty> propertyProvider, final BeanWrapper<?, ?> wrapper) {
|
||||
protected void readPropertyFromRow(final Row row, final CassandraPersistentEntity<?> entity,
|
||||
final CassandraPersistentProperty prop, final CassandraPropertyValueProvider propertyProvider,
|
||||
final BeanWrapper<?, ?> wrapper) {
|
||||
|
||||
if (entity.isConstructorArgument(prop)) { // skip 'cause prop was set in ctor
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop.isCompositePrimaryKey()) {
|
||||
// handle composite primary key properties via recursion into this method
|
||||
throw new UnsupportedOperationException("composite primary keys are TODO");
|
||||
readPropertiesFromRow(prop.getCompositePrimaryKeyEntity(), row, propertyProvider, wrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasValueForProperty = row.getColumnDefinitions().contains(prop.getColumnName());
|
||||
if (!hasValueForProperty) {
|
||||
if (!row.getColumnDefinitions().contains(prop.getColumnName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -174,103 +175,121 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object obj, Object builtStatement) {
|
||||
public void write(Object source, Object sink) {
|
||||
|
||||
if (obj == null) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> beanClassLoaderClass = transformClassToBeanClassLoaderClass(obj.getClass());
|
||||
Class<?> beanClassLoaderClass = transformClassToBeanClassLoaderClass(source.getClass());
|
||||
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(beanClassLoaderClass);
|
||||
|
||||
if (entity == null) {
|
||||
throw new MappingException("No mapping metadata found for " + obj.getClass());
|
||||
throw new MappingException("No mapping metadata found for " + source.getClass());
|
||||
}
|
||||
|
||||
if (builtStatement instanceof Insert) {
|
||||
writeInsertInternal(obj, (Insert) builtStatement, entity);
|
||||
} else if (builtStatement instanceof Update) {
|
||||
writeUpdateInternal(obj, (Update) builtStatement, entity);
|
||||
} else if (builtStatement instanceof Where) {
|
||||
writeDeleteWhereInternal(obj, (Where) builtStatement, entity);
|
||||
if (sink instanceof Insert) {
|
||||
writeInsertFromObject(source, (Insert) sink, entity);
|
||||
} else if (sink instanceof Update) {
|
||||
writeUpdateFromObject(source, (Update) sink, entity);
|
||||
} else if (sink instanceof Where) {
|
||||
writeDeleteWhereFromObject(source, (Where) sink, entity);
|
||||
} else {
|
||||
throw new MappingException("Unknown buildStatement " + builtStatement.getClass().getName());
|
||||
throw new MappingException("Unknown buildStatement " + sink.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInsertInternal(final Object objectToSave, final Insert insert, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
final BeanWrapper<CassandraPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(objectToSave,
|
||||
conversionService);
|
||||
|
||||
// Write the properties
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
Object propertyObj = wrapper.getProperty(prop, prop.getType(), useFieldAccessOnly);
|
||||
|
||||
if (propertyObj != null) {
|
||||
insert.value(prop.getColumnName(), propertyObj);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
protected void writeInsertFromObject(final Object object, final Insert insert, CassandraPersistentEntity<?> entity) {
|
||||
writeInsertFromWrapper(BeanWrapper.<CassandraPersistentEntity<Object>, Object> create(object, conversionService),
|
||||
insert, entity);
|
||||
}
|
||||
|
||||
private void writeUpdateInternal(final Object objectToSave, final Update update, CassandraPersistentEntity<?> entity) {
|
||||
protected void writeInsertFromWrapper(final BeanWrapper<CassandraPersistentEntity<Object>, Object> wrapper,
|
||||
final Insert insert, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
final BeanWrapper<CassandraPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(objectToSave,
|
||||
conversionService);
|
||||
|
||||
// Write the properties
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
Object propertyObj = wrapper.getProperty(prop, prop.getType(), useFieldAccessOnly);
|
||||
Object value = wrapper.getProperty(prop, prop.getType(), useFieldAccessOnly);
|
||||
|
||||
if (propertyObj != null) {
|
||||
if (prop.isIdProperty()) {
|
||||
update.where(QueryBuilder.eq(prop.getColumnName(), propertyObj));
|
||||
if (prop.isCompositePrimaryKey()) {
|
||||
writeInsertFromWrapper(
|
||||
BeanWrapper.<CassandraPersistentEntity<Object>, Object> create(value, conversionService), insert,
|
||||
prop.getCompositePrimaryKeyEntity());
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
insert.value(prop.getColumnName(), value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void writeUpdateFromObject(final Object object, final Update update, CassandraPersistentEntity<?> entity) {
|
||||
writeUpdateFromWrapper(BeanWrapper.<CassandraPersistentEntity<Object>, Object> create(object, conversionService),
|
||||
update, entity);
|
||||
}
|
||||
|
||||
protected void writeUpdateFromWrapper(final BeanWrapper<CassandraPersistentEntity<Object>, Object> wrapper,
|
||||
final Update update, final CassandraPersistentEntity<?> entity) {
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
Object value = wrapper.getProperty(prop, prop.getType(), useFieldAccessOnly);
|
||||
|
||||
if (prop.isCompositePrimaryKey()) {
|
||||
writeUpdateFromWrapper(
|
||||
BeanWrapper.<CassandraPersistentEntity<Object>, Object> create(value, conversionService), update,
|
||||
prop.getCompositePrimaryKeyEntity());
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
if (prop.isIdProperty() || entity.isCompositePrimaryKey()) {
|
||||
update.where(QueryBuilder.eq(prop.getColumnName(), value));
|
||||
} else {
|
||||
update.with(QueryBuilder.set(prop.getColumnName(), propertyObj));
|
||||
update.with(QueryBuilder.set(prop.getColumnName(), value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void writeDeleteWhereInternal(final Object objectToSave, final Where whereId,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
protected void writeDeleteWhereFromObject(final Object object, final Where where, CassandraPersistentEntity<?> entity) {
|
||||
writeDeleteWhereFromWrapper(
|
||||
BeanWrapper.<CassandraPersistentEntity<Object>, Object> create(object, conversionService), where, entity);
|
||||
}
|
||||
|
||||
final BeanWrapper<CassandraPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(objectToSave,
|
||||
conversionService);
|
||||
protected void writeDeleteWhereFromWrapper(final BeanWrapper<CassandraPersistentEntity<Object>, Object> wrapper,
|
||||
final Where where, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
// Write the properties
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
CassandraPersistentProperty idProperty = entity.getIdProperty();
|
||||
Object idValue = wrapper.getProperty(idProperty, idProperty.getType(), useFieldAccessOnly);
|
||||
|
||||
if (prop.isIdProperty()) {
|
||||
if (idValue == null) {
|
||||
String msg = String.format("no id value found in object {}", wrapper.getBean());
|
||||
log.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
Object propertyObj = wrapper.getProperty(prop, prop.getType(), useFieldAccessOnly);
|
||||
|
||||
if (propertyObj != null) {
|
||||
whereId.and(QueryBuilder.eq(prop.getColumnName(), propertyObj));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
if (idProperty.isCompositePrimaryKey()) {
|
||||
writeDeleteWhereFromWrapper(
|
||||
BeanWrapper.<CassandraPersistentEntity<Object>, Object> create(idValue, conversionService), where,
|
||||
idProperty.getCompositePrimaryKeyEntity());
|
||||
return;
|
||||
}
|
||||
|
||||
where.and(QueryBuilder.eq(idProperty.getColumnName(), idValue));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Class<T> transformClassToBeanClassLoaderClass(Class<T> entity) {
|
||||
protected <T> Class<T> transformClassToBeanClassLoaderClass(Class<T> entity) {
|
||||
try {
|
||||
return (Class<T>) ClassUtils.forName(entity.getName(), beanClassLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
@@ -6,7 +6,12 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cassandra.core.SessionCallback;
|
||||
import org.springframework.cassandra.core.cql.generator.AlterTableCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||
import org.springframework.cassandra.core.cql.generator.DropTableCqlGenerator;
|
||||
import org.springframework.cassandra.core.keyspace.AlterTableSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateTableSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.DropTableSpecification;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
@@ -60,7 +65,9 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
||||
|
||||
@Override
|
||||
public void replaceTable(String tableName, Class<?> entityClass, Map<String, Object> optionsByName) {
|
||||
throw new UnsupportedOperationException("not yet implemented");
|
||||
|
||||
dropTable(tableName);
|
||||
createTable(false, tableName, entityClass, optionsByName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,15 +109,7 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
||||
|
||||
log.info("Dropping table => " + tableName);
|
||||
|
||||
final String q = CqlUtils.dropTable(tableName);
|
||||
log.info(q);
|
||||
|
||||
execute(new SessionCallback<ResultSet>() {
|
||||
@Override
|
||||
public ResultSet doInSession(Session s) {
|
||||
return s.execute(q);
|
||||
}
|
||||
});
|
||||
execute(DropTableSpecification.dropTable(tableName));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,7 +30,6 @@ import com.datastax.driver.core.querybuilder.Select;
|
||||
* @author Alex Shvid
|
||||
* @author David Webb
|
||||
* @author Matthew Adams
|
||||
*
|
||||
*/
|
||||
public interface CassandraOperations extends CqlOperations {
|
||||
|
||||
@@ -58,9 +57,10 @@ public interface CassandraOperations extends CqlOperations {
|
||||
* @param selectClass must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
*/
|
||||
|
||||
<T> List<T> select(Select selectQuery, Class<T> selectClass);
|
||||
|
||||
<T> T selectOneById(Class<T> selectClass, Object id);
|
||||
|
||||
/**
|
||||
* Execute query and convert ResultSet to the entity
|
||||
*
|
||||
@@ -72,13 +72,14 @@ public interface CassandraOperations extends CqlOperations {
|
||||
|
||||
<T> T selectOne(Select selectQuery, Class<T> selectClass);
|
||||
|
||||
Long countById(Class<?> clazz, Object id);
|
||||
|
||||
/**
|
||||
* Counts rows for given query
|
||||
*
|
||||
* @param selectQuery
|
||||
* @return
|
||||
*/
|
||||
|
||||
Long count(Select selectQuery);
|
||||
|
||||
/**
|
||||
@@ -87,7 +88,6 @@ public interface CassandraOperations extends CqlOperations {
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
|
||||
Long count(String tableName);
|
||||
|
||||
/**
|
||||
@@ -457,4 +457,8 @@ public interface CassandraOperations extends CqlOperations {
|
||||
* @return
|
||||
*/
|
||||
CassandraConverter getConverter();
|
||||
|
||||
void deleteById(Class<?> clazz, Object id);
|
||||
|
||||
<T> List<T> selectByIds(Class<T> clazz, Iterable<?> ids);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.cassandra.core.CqlTemplate;
|
||||
import org.springframework.cassandra.core.QueryOptions;
|
||||
@@ -30,53 +27,48 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.exception.EntityWriterException;
|
||||
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
|
||||
import org.springframework.data.cassandra.util.CqlUtils;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.convert.EntityWriter;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.datastax.driver.core.Query;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.querybuilder.Batch;
|
||||
import com.datastax.driver.core.querybuilder.Clause;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Delete.Where;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
|
||||
/**
|
||||
* The Cassandra Data Template is a convenience API for all Cassandra Operations using POJOs. For low level Cassandra
|
||||
* Operations use the {@link CqlTemplate}
|
||||
* The CassandraTemplate is a convenient API for all Cassandra operations using POJOs with their Spring Data Cassandra
|
||||
* mapping information. For low-level Cassandra operation, see {@link CqlTemplate}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author David Webb
|
||||
* @author Matthew T. Adams
|
||||
*
|
||||
* @see CqlTemplate
|
||||
*/
|
||||
public class CassandraTemplate extends CqlTemplate implements CassandraOperations {
|
||||
|
||||
/*
|
||||
* List of iterable classes when testing POJOs for specific operations.
|
||||
*/
|
||||
public static final Collection<String> ITERABLE_CLASSES;
|
||||
static {
|
||||
|
||||
Set<String> iterableClasses = new HashSet<String>();
|
||||
iterableClasses.add(List.class.getName());
|
||||
iterableClasses.add(Collection.class.getName());
|
||||
iterableClasses.add(Iterator.class.getName());
|
||||
|
||||
ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Required elements for successful Template Operations. These can be set with the Constructor, or wired in
|
||||
* later.
|
||||
*/
|
||||
private CassandraConverter cassandraConverter;
|
||||
private CassandraMappingContext mappingContext;
|
||||
private boolean useFieldAccessOnly = false;
|
||||
|
||||
/**
|
||||
* Default Constructor for wiring in the required components later
|
||||
@@ -84,15 +76,6 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
public CassandraTemplate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor if only session is known at time of Template Creation
|
||||
*
|
||||
* @param session must not be {@literal null}
|
||||
*/
|
||||
public CassandraTemplate(Session session) {
|
||||
this(session, new MappingCassandraConverter(new DefaultCassandraMappingContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor if only session and converter are known at time of Template Creation
|
||||
*
|
||||
@@ -101,23 +84,60 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
*/
|
||||
public CassandraTemplate(Session session, CassandraConverter converter) {
|
||||
setSession(session);
|
||||
this.cassandraConverter = converter;
|
||||
this.mappingContext = cassandraConverter.getCassandraMappingContext();
|
||||
setConverter(converter);
|
||||
}
|
||||
|
||||
public void setConverter(CassandraConverter cassandraConverter) {
|
||||
|
||||
Assert.notNull(cassandraConverter);
|
||||
this.cassandraConverter = cassandraConverter;
|
||||
mappingContext = cassandraConverter.getCassandraMappingContext();
|
||||
Assert.notNull(mappingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraConverter getConverter() {
|
||||
return cassandraConverter;
|
||||
}
|
||||
|
||||
public CassandraMappingContext getCassandraMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
Assert.notNull(cassandraConverter);
|
||||
Assert.notNull(mappingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countById(Class<?> clazz, Object id) {
|
||||
|
||||
Assert.notNull(clazz);
|
||||
Assert.notNull(id);
|
||||
|
||||
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(clazz);
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException(String.format("unknown persistent class [%s]", clazz.getName()));
|
||||
}
|
||||
|
||||
Select select = QueryBuilder.select().countAll().from(entity.getTableName());
|
||||
appendIdCriteria(select.where(), entity, id);
|
||||
|
||||
return count(select);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long count(Select selectQuery) {
|
||||
return doSelectCount(selectQuery);
|
||||
return selectCount(selectQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long count(String tableName) {
|
||||
Select select = QueryBuilder.select().countAll().from(tableName);
|
||||
return doSelectCount(select);
|
||||
return selectCount(select);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,7 +156,6 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
|
||||
@Override
|
||||
public <T> void delete(List<T> entities, String tableName) {
|
||||
|
||||
delete(entities, tableName, null);
|
||||
}
|
||||
|
||||
@@ -145,7 +164,21 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entities);
|
||||
Assert.notEmpty(entities);
|
||||
Assert.notNull(tableName);
|
||||
doBatchDelete(tableName, entities, options, false);
|
||||
batchDelete(tableName, entities, options, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(Class<?> clazz, Object id) {
|
||||
|
||||
Assert.notNull(clazz);
|
||||
Assert.notNull(id);
|
||||
|
||||
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(clazz);
|
||||
|
||||
Delete delete = QueryBuilder.delete().all().from(entity.getTableName());
|
||||
appendIdCriteria(delete.where(), entity, id);
|
||||
|
||||
execute(delete.getQueryString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,7 +204,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
public <T> void delete(T entity, String tableName, QueryOptions options) {
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(tableName);
|
||||
doDelete(tableName, entity, options, false);
|
||||
delete(tableName, entity, options, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,7 +231,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entities);
|
||||
Assert.notEmpty(entities);
|
||||
Assert.notNull(tableName);
|
||||
doBatchDelete(tableName, entities, options, true);
|
||||
batchDelete(tableName, entities, options, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,7 +257,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
public <T> void deleteAsynchronously(T entity, String tableName, QueryOptions options) {
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(tableName);
|
||||
doDelete(tableName, entity, options, true);
|
||||
delete(tableName, entity, options, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,11 +279,6 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
return entity.getTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraConverter getConverter() {
|
||||
return cassandraConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName(Class<?> entityClass) {
|
||||
return determineTableName(entityClass);
|
||||
@@ -280,7 +308,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entities);
|
||||
Assert.notEmpty(entities);
|
||||
Assert.notNull(tableName);
|
||||
return doBatchInsert(tableName, entities, options, false);
|
||||
return batchInsert(tableName, entities, options, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -307,7 +335,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(tableName);
|
||||
ensureNotIterable(entity);
|
||||
return doInsert(tableName, entity, options, false);
|
||||
return insert(tableName, entity, options, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -334,7 +362,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entities);
|
||||
Assert.notEmpty(entities);
|
||||
Assert.notNull(tableName);
|
||||
return doBatchInsert(tableName, entities, options, true);
|
||||
return batchInsert(tableName, entities, options, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -363,7 +391,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
|
||||
ensureNotIterable(entity);
|
||||
|
||||
return doInsert(tableName, entity, options, true);
|
||||
return insert(tableName, entity, options, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -373,7 +401,108 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
|
||||
@Override
|
||||
public <T> List<T> select(String cql, Class<T> selectClass) {
|
||||
return doSelect(cql, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
return select(cql, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public <T> List<T> selectByIds(Class<T> clazz, Iterable<?> ids) {
|
||||
|
||||
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(clazz);
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException(String.format("unknown persistent entity class [%s]", clazz.getName()));
|
||||
}
|
||||
if (entity.getIdProperty().isCompositePrimaryKey()) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"entity class [%s] uses a composite primary key class [%s] which this method can't support", clazz.getName(),
|
||||
entity.getIdProperty().getCompositePrimaryKeyEntity().getType().getName()));
|
||||
}
|
||||
|
||||
List idList = null;
|
||||
if (ids instanceof List) {
|
||||
idList = (List) ids;
|
||||
} else {
|
||||
idList = new ArrayList();
|
||||
for (Object id : ids) {
|
||||
idList.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
Select select = QueryBuilder.select().all().from(entity.getTableName());
|
||||
select.where(QueryBuilder.in(entity.getIdProperty().getColumnName(), idList.toArray()));
|
||||
|
||||
return select(select, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T selectOneById(Class<T> selectClass, Object id) {
|
||||
|
||||
Assert.notNull(selectClass);
|
||||
Assert.notNull(id);
|
||||
|
||||
CassandraPersistentEntity<?> entityClass = mappingContext.getPersistentEntity(selectClass);
|
||||
if (entityClass == null) {
|
||||
throw new IllegalArgumentException(String.format("unknown entity class [%s]", selectClass.getName()));
|
||||
}
|
||||
|
||||
Select select = QueryBuilder.select().all().from(entityClass.getTableName());
|
||||
appendIdCriteria(select.where(), entityClass, id);
|
||||
|
||||
return selectOne(select, selectClass);
|
||||
}
|
||||
|
||||
protected interface ClauseCallback {
|
||||
void onClause(Clause clause);
|
||||
}
|
||||
|
||||
protected void appendIdCriteria(final ClauseCallback clauseCallback, CassandraPersistentEntity<?> entity, Object id) {
|
||||
|
||||
CassandraPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if (idProperty.isCompositePrimaryKey()) {
|
||||
|
||||
CassandraPersistentEntity<?> idEntity = idProperty.getCompositePrimaryKeyEntity();
|
||||
|
||||
final BeanWrapper<CassandraPersistentEntity<Object>, Object> idWrapper = BeanWrapper
|
||||
.<CassandraPersistentEntity<Object>, Object> create(id, cassandraConverter.getConversionService());
|
||||
|
||||
idEntity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty p) {
|
||||
|
||||
clauseCallback.onClause(QueryBuilder.eq(p.getColumnName(),
|
||||
idWrapper.getProperty(p, p.getActualType(), useFieldAccessOnly)));
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
clauseCallback.onClause(QueryBuilder.eq(idProperty.getColumnName(), id));
|
||||
}
|
||||
|
||||
protected void appendIdCriteria(final com.datastax.driver.core.querybuilder.Select.Where where,
|
||||
CassandraPersistentEntity<?> entity, Object id) {
|
||||
|
||||
appendIdCriteria(new ClauseCallback() {
|
||||
|
||||
@Override
|
||||
public void onClause(Clause clause) {
|
||||
where.and(clause);
|
||||
}
|
||||
}, entity, id);
|
||||
}
|
||||
|
||||
protected void appendIdCriteria(final Where where, CassandraPersistentEntity<?> entity, Object id) {
|
||||
|
||||
appendIdCriteria(new ClauseCallback() {
|
||||
|
||||
@Override
|
||||
public void onClause(Clause clause) {
|
||||
where.and(clause);
|
||||
}
|
||||
}, entity, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -383,7 +512,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
|
||||
@Override
|
||||
public <T> T selectOne(String cql, Class<T> selectClass) {
|
||||
return doSelectOne(cql, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
return selectOne(cql, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -410,7 +539,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entities);
|
||||
Assert.notEmpty(entities);
|
||||
Assert.notNull(tableName);
|
||||
return doBatchUpdate(tableName, entities, options, false);
|
||||
return batchUpdate(tableName, entities, options, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -436,7 +565,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
public <T> T update(T entity, String tableName, QueryOptions options) {
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(tableName);
|
||||
return doUpdate(tableName, entity, options, false);
|
||||
return update(tableName, entity, options, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -463,7 +592,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
Assert.notNull(entities);
|
||||
Assert.notEmpty(entities);
|
||||
Assert.notNull(tableName);
|
||||
return doBatchUpdate(tableName, entities, options, true);
|
||||
return batchUpdate(tableName, entities, options, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -490,7 +619,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
public <T> T updateAsynchronously(T entity, String tableName, QueryOptions options) {
|
||||
Assert.notNull(entity);
|
||||
Assert.notNull(tableName);
|
||||
return doUpdate(tableName, entity, options, true);
|
||||
return update(tableName, entity, options, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -505,12 +634,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param query
|
||||
* @param readRowCallback
|
||||
* @return
|
||||
*/
|
||||
private <T> List<T> doSelect(final String query, ReadRowCallback<T> readRowCallback) {
|
||||
private <T> List<T> select(final String query, ReadRowCallback<T> readRowCallback) {
|
||||
|
||||
ResultSet resultSet = doExecute(new SessionCallback<ResultSet>() {
|
||||
|
||||
@@ -534,11 +658,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selectQuery
|
||||
* @return
|
||||
*/
|
||||
private Long doSelectCount(final Select query) {
|
||||
private Long selectCount(final Select query) {
|
||||
|
||||
Long count = null;
|
||||
|
||||
@@ -569,7 +689,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param readRowCallback
|
||||
* @return
|
||||
*/
|
||||
private <T> T doSelectOne(final String query, ReadRowCallback<T> readRowCallback) {
|
||||
private <T> T selectOne(final String query, ReadRowCallback<T> readRowCallback) {
|
||||
|
||||
logger.info(query);
|
||||
|
||||
@@ -607,36 +727,29 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param tableName
|
||||
* @param objectToRemove
|
||||
*/
|
||||
protected <T> void doBatchDelete(final String tableName, final List<T> entities, final QueryOptions options,
|
||||
protected <T> void batchDelete(final String tableName, final List<T> entities, final QueryOptions options,
|
||||
final boolean deleteAsynchronously) {
|
||||
|
||||
Assert.notEmpty(entities);
|
||||
|
||||
try {
|
||||
final Batch b = createDeleteBatchQuery(tableName, entities, options, cassandraConverter);
|
||||
logger.info(b.toString());
|
||||
|
||||
final Batch b = CqlUtils.toDeleteBatchQuery(tableName, entities, options, cassandraConverter);
|
||||
logger.info(b.toString());
|
||||
doExecute(new SessionCallback<Object>() {
|
||||
|
||||
doExecute(new SessionCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (deleteAsynchronously) {
|
||||
s.executeAsync(b);
|
||||
} else {
|
||||
s.execute(b);
|
||||
}
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public Object doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (deleteAsynchronously) {
|
||||
s.executeAsync(b);
|
||||
} else {
|
||||
s.execute(b);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (EntityWriterException e) {
|
||||
throw getExceptionTranslator().translateExceptionIfPossible(
|
||||
new RuntimeException("Failed to translate Object to Query", e));
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -648,36 +761,29 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param insertAsychronously
|
||||
* @return
|
||||
*/
|
||||
protected <T> List<T> doBatchInsert(final String tableName, final List<T> entities, final QueryOptions options,
|
||||
protected <T> List<T> batchInsert(final String tableName, final List<T> entities, final QueryOptions options,
|
||||
final boolean insertAsychronously) {
|
||||
|
||||
Assert.notEmpty(entities);
|
||||
|
||||
try {
|
||||
final Batch b = createInsertBatchQuery(tableName, entities, options, cassandraConverter);
|
||||
logger.info(b.getQueryString());
|
||||
|
||||
final Batch b = CqlUtils.toInsertBatchQuery(tableName, entities, options, cassandraConverter);
|
||||
logger.info(b.getQueryString());
|
||||
return doExecute(new SessionCallback<List<T>>() {
|
||||
|
||||
return doExecute(new SessionCallback<List<T>>() {
|
||||
|
||||
@Override
|
||||
public List<T> doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (insertAsychronously) {
|
||||
s.executeAsync(b);
|
||||
} else {
|
||||
s.execute(b);
|
||||
}
|
||||
|
||||
return entities;
|
||||
@Override
|
||||
public List<T> doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (insertAsychronously) {
|
||||
s.executeAsync(b);
|
||||
} else {
|
||||
s.execute(b);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (EntityWriterException e) {
|
||||
throw getExceptionTranslator().translateExceptionIfPossible(
|
||||
new RuntimeException("Failed to translate Object to Query", e));
|
||||
}
|
||||
return entities;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -689,36 +795,29 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param updateAsychronously
|
||||
* @return
|
||||
*/
|
||||
protected <T> List<T> doBatchUpdate(final String tableName, final List<T> entities, final QueryOptions options,
|
||||
protected <T> List<T> batchUpdate(final String tableName, final List<T> entities, final QueryOptions options,
|
||||
final boolean updateAsychronously) {
|
||||
|
||||
Assert.notEmpty(entities);
|
||||
|
||||
try {
|
||||
final Batch b = toUpdateBatchQuery(tableName, entities, options, cassandraConverter);
|
||||
logger.info(b.toString());
|
||||
|
||||
final Batch b = CqlUtils.toUpdateBatchQuery(tableName, entities, options, cassandraConverter);
|
||||
logger.info(b.toString());
|
||||
return doExecute(new SessionCallback<List<T>>() {
|
||||
|
||||
return doExecute(new SessionCallback<List<T>>() {
|
||||
|
||||
@Override
|
||||
public List<T> doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (updateAsychronously) {
|
||||
s.executeAsync(b);
|
||||
} else {
|
||||
s.execute(b);
|
||||
}
|
||||
|
||||
return entities;
|
||||
@Override
|
||||
public List<T> doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (updateAsychronously) {
|
||||
s.executeAsync(b);
|
||||
} else {
|
||||
s.execute(b);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (EntityWriterException e) {
|
||||
throw getExceptionTranslator().translateExceptionIfPossible(
|
||||
new RuntimeException("Failed to translate Object to Query", e));
|
||||
}
|
||||
return entities;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -727,54 +826,26 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param tableName
|
||||
* @param objectToRemove
|
||||
*/
|
||||
protected <T> void doDelete(final String tableName, final T objectToRemove, final QueryOptions options,
|
||||
protected <T> void delete(final String tableName, final T objectToRemove, final QueryOptions options,
|
||||
final boolean deleteAsynchronously) {
|
||||
|
||||
try {
|
||||
final Query q = createDeleteQuery(tableName, objectToRemove, options, cassandraConverter);
|
||||
logger.info(q.toString());
|
||||
|
||||
final Query q = CqlUtils.toDeleteQuery(tableName, objectToRemove, options, cassandraConverter);
|
||||
logger.info(q.toString());
|
||||
doExecute(new SessionCallback<Object>() {
|
||||
|
||||
doExecute(new SessionCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (deleteAsynchronously) {
|
||||
s.executeAsync(q);
|
||||
} else {
|
||||
s.execute(q);
|
||||
}
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public Object doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (deleteAsynchronously) {
|
||||
s.executeAsync(q);
|
||||
} else {
|
||||
s.execute(q);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (EntityWriterException e) {
|
||||
throw getExceptionTranslator().translateExceptionIfPossible(
|
||||
new RuntimeException("Failed to translate Object to Query", e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command at the Session Level
|
||||
*
|
||||
* @param callback
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected <T> T doExecute(SessionCallback<T> callback) {
|
||||
|
||||
Assert.notNull(callback);
|
||||
|
||||
try {
|
||||
|
||||
return callback.doInSession(getSession());
|
||||
|
||||
} catch (DataAccessException e) {
|
||||
throw translateExceptionIfPossible(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -783,42 +854,34 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param tableName
|
||||
* @param entity
|
||||
*/
|
||||
protected <T> T doInsert(final String tableName, final T entity, final QueryOptions options,
|
||||
protected <T> T insert(final String tableName, final T entity, final QueryOptions options,
|
||||
final boolean insertAsychronously) {
|
||||
|
||||
try {
|
||||
final Query q = createInsertQuery(tableName, entity, options, cassandraConverter);
|
||||
|
||||
final Query q = CqlUtils.toInsertQuery(tableName, entity, options, cassandraConverter);
|
||||
|
||||
logger.info(q.toString());
|
||||
if (q.getConsistencyLevel() != null) {
|
||||
logger.info(q.getConsistencyLevel().name());
|
||||
}
|
||||
if (q.getRetryPolicy() != null) {
|
||||
logger.info(q.getRetryPolicy().toString());
|
||||
}
|
||||
|
||||
return doExecute(new SessionCallback<T>() {
|
||||
|
||||
@Override
|
||||
public T doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (insertAsychronously) {
|
||||
s.executeAsync(q);
|
||||
} else {
|
||||
s.execute(q);
|
||||
}
|
||||
|
||||
return entity;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
} catch (EntityWriterException e) {
|
||||
throw getExceptionTranslator().translateExceptionIfPossible(
|
||||
new RuntimeException("Failed to translate Object to Query", e));
|
||||
logger.info(q.toString());
|
||||
if (q.getConsistencyLevel() != null) {
|
||||
logger.info(q.getConsistencyLevel().name());
|
||||
}
|
||||
if (q.getRetryPolicy() != null) {
|
||||
logger.info(q.getRetryPolicy().toString());
|
||||
}
|
||||
|
||||
return doExecute(new SessionCallback<T>() {
|
||||
|
||||
@Override
|
||||
public T doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (insertAsychronously) {
|
||||
s.executeAsync(q);
|
||||
} else {
|
||||
s.execute(q);
|
||||
}
|
||||
|
||||
return entity;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -830,35 +893,27 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param updateAsychronously
|
||||
* @return
|
||||
*/
|
||||
protected <T> T doUpdate(final String tableName, final T entity, final QueryOptions options,
|
||||
protected <T> T update(final String tableName, final T entity, final QueryOptions options,
|
||||
final boolean updateAsychronously) {
|
||||
|
||||
try {
|
||||
final Query q = toUpdateQuery(tableName, entity, options, cassandraConverter);
|
||||
logger.info(q.toString());
|
||||
|
||||
final Query q = CqlUtils.toUpdateQuery(tableName, entity, options, cassandraConverter);
|
||||
logger.info(q.toString());
|
||||
return doExecute(new SessionCallback<T>() {
|
||||
|
||||
return doExecute(new SessionCallback<T>() {
|
||||
|
||||
@Override
|
||||
public T doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (updateAsychronously) {
|
||||
s.executeAsync(q);
|
||||
} else {
|
||||
s.execute(q);
|
||||
}
|
||||
|
||||
return entity;
|
||||
@Override
|
||||
public T doInSession(Session s) throws DataAccessException {
|
||||
|
||||
if (updateAsychronously) {
|
||||
s.executeAsync(q);
|
||||
} else {
|
||||
s.execute(q);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (EntityWriterException e) {
|
||||
throw getExceptionTranslator().translateExceptionIfPossible(
|
||||
new RuntimeException("Failed to translate Object to Query", e));
|
||||
}
|
||||
return entity;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -867,10 +922,197 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
|
||||
* @param o
|
||||
*/
|
||||
protected void ensureNotIterable(Object o) {
|
||||
if (null != o) {
|
||||
if (o.getClass().isArray() || ITERABLE_CLASSES.contains(o.getClass().getName())) {
|
||||
throw new IllegalArgumentException("Cannot use a collection here.");
|
||||
}
|
||||
|
||||
if (null == o) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (o.getClass().isArray() || (o instanceof Iterable) || (o instanceof Iterator)) {
|
||||
throw new IllegalArgumentException("cannot use a multivalued object here.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Query Object for an insert
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
public static Query createInsertQuery(String tableName, final Object objectToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
final Insert q = QueryBuilder.insertInto(tableName);
|
||||
|
||||
/*
|
||||
* Write properties
|
||||
*/
|
||||
entityWriter.write(objectToSave, q);
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(q, options);
|
||||
|
||||
/*
|
||||
* Add TTL to Insert object
|
||||
*/
|
||||
if (options != null && options.getTtl() != null) {
|
||||
q.using(QueryBuilder.ttl(options.getTtl()));
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Query Object for an Update
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
public static Query toUpdateQuery(String tableName, final Object objectToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
final Update q = QueryBuilder.update(tableName);
|
||||
|
||||
/*
|
||||
* Write properties
|
||||
*/
|
||||
entityWriter.write(objectToSave, q);
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(q, options);
|
||||
|
||||
/*
|
||||
* Add TTL to Insert object
|
||||
*/
|
||||
if (options != null && options.getTtl() != null) {
|
||||
q.using(QueryBuilder.ttl(options.getTtl()));
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Batch Object for multiple Updates
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectsToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
public static <T> Batch toUpdateBatchQuery(final String tableName, final List<T> objectsToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
/*
|
||||
* Return variable is a Batch statement
|
||||
*/
|
||||
final Batch b = QueryBuilder.batch();
|
||||
|
||||
for (final T objectToSave : objectsToSave) {
|
||||
|
||||
b.add((Statement) toUpdateQuery(tableName, objectToSave, options, entityWriter));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(b, options);
|
||||
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Batch Object for multiple inserts
|
||||
*
|
||||
* @param tableName
|
||||
* @param entities
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
public static <T> Batch createInsertBatchQuery(final String tableName, final List<T> entities, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
Batch batch = QueryBuilder.batch();
|
||||
|
||||
for (T entity : entities) {
|
||||
batch.add((Statement) createInsertQuery(tableName, entity, options, entityWriter));
|
||||
}
|
||||
|
||||
CqlTemplate.addQueryOptions(batch, options);
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Delete Query Object from an annotated POJO
|
||||
*
|
||||
* @param tableName
|
||||
* @param object
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
* @return
|
||||
*/
|
||||
public static Query createDeleteQuery(String tableName, final Object object, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
Delete.Selection ds = QueryBuilder.delete();
|
||||
Delete q = ds.from(tableName);
|
||||
Where w = q.where();
|
||||
|
||||
entityWriter.write(object, w);
|
||||
|
||||
CqlTemplate.addQueryOptions(q, options);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Batch Query object for multiple deletes.
|
||||
*
|
||||
* @param tableName
|
||||
* @param entities
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static <T> Batch createDeleteBatchQuery(String tableName, List<T> entities, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
Batch batch = QueryBuilder.batch();
|
||||
|
||||
for (T entity : entities) {
|
||||
batch.add((Statement) createDeleteQuery(tableName, entity, options, entityWriter));
|
||||
}
|
||||
|
||||
CqlTemplate.addQueryOptions(batch, options);
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
public boolean getUseFieldAccessOnly() {
|
||||
return useFieldAccessOnly;
|
||||
}
|
||||
|
||||
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
|
||||
this.useFieldAccessOnly = useFieldAccessOnly;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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
|
||||
*
|
||||
* http://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.exception;
|
||||
|
||||
/**
|
||||
* Exception to handle failing to write a PersistedEntity to a CQL String or Query object
|
||||
*
|
||||
* @author David Webb
|
||||
*
|
||||
*/
|
||||
public class EntityWriterException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -3068204776019978031L;
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
public EntityWriterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public EntityWriterException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public EntityWriterException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.cassandra.support.exception.UnsupportedCassandraOperationException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -24,6 +27,7 @@ import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.data.cassandra.util.CassandraNamingUtils;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.Expression;
|
||||
@@ -34,8 +38,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Cassandra specific {@link BasicPersistentEntity} implementation that adds Cassandra specific metadata such as the
|
||||
* table name.
|
||||
* Cassandra specific {@link BasicPersistentEntity} implementation that adds Cassandra specific metadata.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
@@ -43,10 +46,14 @@ import org.springframework.util.StringUtils;
|
||||
public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T, CassandraPersistentProperty> implements
|
||||
CassandraPersistentEntity<T>, ApplicationContextAware {
|
||||
|
||||
private String tableName;
|
||||
private final SpelExpressionParser spelParser;
|
||||
private final StandardEvaluationContext spelContext;
|
||||
private final Class<T> type;
|
||||
protected String tableName;
|
||||
protected CassandraMappingContext mappingContext;
|
||||
protected final SpelExpressionParser spelParser;
|
||||
protected final StandardEvaluationContext spelContext;
|
||||
|
||||
public BasicCassandraPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
this(typeInformation, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicCassandraPersistentEntity} with the given {@link TypeInformation}. Will default the table
|
||||
@@ -54,23 +61,22 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
|
||||
*
|
||||
* @param typeInformation
|
||||
*/
|
||||
public BasicCassandraPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
public BasicCassandraPersistentEntity(TypeInformation<T> typeInformation, CassandraMappingContext mappingContext) {
|
||||
|
||||
super(typeInformation, DefaultCassandraPersistentPropertyColumnComparator.IT);
|
||||
super(typeInformation, CassandraPersistentPropertyComparator.IT);
|
||||
|
||||
this.spelParser = new SpelExpressionParser();
|
||||
this.spelContext = new StandardEvaluationContext();
|
||||
|
||||
this.type = typeInformation.getType();
|
||||
this.mappingContext = mappingContext;
|
||||
|
||||
determineTableName();
|
||||
}
|
||||
|
||||
protected void determineTableName() {
|
||||
Table anno = type.getAnnotation(Table.class);
|
||||
Table anno = getType().getAnnotation(Table.class);
|
||||
|
||||
this.tableName = anno != null && StringUtils.hasText(anno.value()) ? anno.value() : CassandraNamingUtils
|
||||
.getPreferredTableName(type);
|
||||
.getPreferredTableName(getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,4 +108,46 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
|
||||
Assert.hasText(tableName);
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraMappingContext getMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompositePrimaryKey() {
|
||||
return getType().isAnnotationPresent(PrimaryKeyClass.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CassandraPersistentProperty> getCompositePrimaryKeyProperties() {
|
||||
|
||||
final List<CassandraPersistentProperty> properties = new ArrayList<CassandraPersistentProperty>();
|
||||
|
||||
if (!isCompositePrimaryKey()) {
|
||||
throw new IllegalStateException(String.format("[%s] does not represent a composite primary key class", this
|
||||
.getType().getName()));
|
||||
}
|
||||
|
||||
addCompositePrimaryKeyProperties(this, properties);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected void addCompositePrimaryKeyProperties(CassandraPersistentEntity<?> compositePrimaryKeyEntity,
|
||||
final List<CassandraPersistentProperty> properties) {
|
||||
|
||||
compositePrimaryKeyEntity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty p) {
|
||||
|
||||
if (p.isCompositePrimaryKey()) {
|
||||
addCompositePrimaryKeyProperties(p.getCompositePrimaryKeyEntity(), properties);
|
||||
} else {
|
||||
properties.add(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -24,6 +25,7 @@ import org.springframework.cassandra.core.Ordering;
|
||||
import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -49,15 +51,20 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
*/
|
||||
public BasicCassandraPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
CassandraPersistentEntity<?> owner, CassandraSimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraPersistentEntity<?> getOwner() {
|
||||
return (CassandraPersistentEntity<?>) super.getOwner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompositePrimaryKey() {
|
||||
return getField().getType().isAnnotationPresent(PrimaryKeyClass.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getCompositePrimaryKeyType() {
|
||||
if (!isCompositePrimaryKey()) {
|
||||
return null;
|
||||
@@ -67,31 +74,23 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraPersistentEntity<?> getCompositePrimaryKeyEntity() {
|
||||
public TypeInformation<?> getCompositePrimaryKeyTypeInformation() {
|
||||
if (!isCompositePrimaryKey()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (CassandraPersistentEntity<?>) ClassTypeInformation.from(getCompositePrimaryKeyType());
|
||||
return ClassTypeInformation.from(getCompositePrimaryKeyType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
|
||||
// first check @Column annotation
|
||||
Column column = findAnnotation(Column.class);
|
||||
if (column != null && StringUtils.hasText(column.value())) {
|
||||
return column.value();
|
||||
List<String> columnNames = getColumnNames();
|
||||
if (columnNames.size() != 1) {
|
||||
throw new IllegalStateException("property does not have a single column mapping");
|
||||
}
|
||||
|
||||
// else check @PrimaryKeyColumn annotation
|
||||
PrimaryKeyColumn pk = findAnnotation(PrimaryKeyColumn.class);
|
||||
if (pk != null && StringUtils.hasText(pk.name())) {
|
||||
return pk.name();
|
||||
}
|
||||
|
||||
// else default
|
||||
return field.getName().toLowerCase(); // TODO: replace with naming strategy class
|
||||
return columnNames.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,11 +198,6 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
return isAnnotationPresent(PrimaryKeyColumn.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<CassandraPersistentProperty> createAssociation() {
|
||||
return new Association<CassandraPersistentProperty>(this, null);
|
||||
}
|
||||
|
||||
protected DataType getDataTypeFor(DataType.Name typeName) {
|
||||
DataType dataType = CassandraSimpleTypeHolder.getDataTypeFor(typeName);
|
||||
if (dataType == null) {
|
||||
@@ -230,4 +224,79 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
|
||||
+ this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getColumnNames() {
|
||||
|
||||
final List<String> columnNames = new ArrayList<String>();
|
||||
|
||||
if (isCompositePrimaryKey()) {
|
||||
addCompositePrimaryKeyColumnNames(getCompositePrimaryKeyEntity(), columnNames);
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
// else not a composite primary key property -- first check @Column annotation
|
||||
Column column = findAnnotation(Column.class);
|
||||
if (column != null && StringUtils.hasText(column.value())) {
|
||||
columnNames.add(column.value());
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
// else check @PrimaryKeyColumn annotation
|
||||
PrimaryKeyColumn pk = findAnnotation(PrimaryKeyColumn.class);
|
||||
if (pk != null && StringUtils.hasText(pk.name())) {
|
||||
columnNames.add(pk.name());
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
// else default
|
||||
columnNames.add(field.getName().toLowerCase()); // TODO: replace with naming strategy class
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
protected void addCompositePrimaryKeyColumnNames(CassandraPersistentEntity<?> compositePrimaryKeyEntity,
|
||||
final List<String> columnNames) {
|
||||
|
||||
compositePrimaryKeyEntity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty p) {
|
||||
if (p.isCompositePrimaryKey()) {
|
||||
addCompositePrimaryKeyColumnNames(p.getCompositePrimaryKeyEntity(), columnNames);
|
||||
} else {
|
||||
columnNames.add(p.getColumnName());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CassandraPersistentProperty> getCompositePrimaryKeyProperties() {
|
||||
|
||||
if (!isCompositePrimaryKey()) {
|
||||
throw new IllegalStateException(String.format("[%s] does not represent a composite primary key property",
|
||||
getField()));
|
||||
}
|
||||
|
||||
return getCompositePrimaryKeyEntity().getCompositePrimaryKeyProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraPersistentEntity<?> getCompositePrimaryKeyEntity() {
|
||||
CassandraMappingContext mappingContext = getOwner().getMappingContext();
|
||||
if (mappingContext == null) {
|
||||
throw new IllegalStateException("need CassandraMappingContext");
|
||||
}
|
||||
return mappingContext.getPersistentEntity(getCompositePrimaryKeyTypeInformation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Association<CassandraPersistentProperty> getAssociation() {
|
||||
throw new UnsupportedOperationException("Cassandra does not support associations");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Association<CassandraPersistentProperty> createAssociation() {
|
||||
return new Association<CassandraPersistentProperty>(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
public class CachingCassandraPersistentEntity<T> extends BasicCassandraPersistentEntity<T> {
|
||||
|
||||
protected String tableName;
|
||||
protected String name;
|
||||
protected Boolean isCompositePrimaryKey;
|
||||
protected List<CassandraPersistentProperty> compositePrimaryKeyProperties;
|
||||
protected Map<String, CassandraPersistentProperty> properties = new HashMap<String, CassandraPersistentProperty>();
|
||||
|
||||
public CachingCassandraPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
super(typeInformation);
|
||||
}
|
||||
|
||||
public CachingCassandraPersistentEntity(TypeInformation<T> typeInformation, CassandraMappingContext mappingContext) {
|
||||
super(typeInformation, mappingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName() {
|
||||
if (tableName == null) {
|
||||
tableName = super.getTableName();
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
name = super.getName();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompositePrimaryKey() {
|
||||
if (isCompositePrimaryKey == null) {
|
||||
isCompositePrimaryKey = super.isCompositePrimaryKey();
|
||||
}
|
||||
return isCompositePrimaryKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CassandraPersistentProperty> getCompositePrimaryKeyProperties() {
|
||||
if (compositePrimaryKeyProperties == null) {
|
||||
compositePrimaryKeyProperties = super.getCompositePrimaryKeyProperties();
|
||||
}
|
||||
return compositePrimaryKeyProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraPersistentProperty getPersistentProperty(String name) {
|
||||
if (properties.get(name) == null) {
|
||||
properties.put(name, super.getPersistentProperty(name));
|
||||
}
|
||||
return properties.get(name);
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,10 @@ package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cassandra.core.Ordering;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
@@ -37,11 +39,12 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent
|
||||
private Boolean isClusterKeyColumn;
|
||||
private Boolean isPrimaryKeyColumn;
|
||||
private String columnName;
|
||||
private List<String> columnNames;
|
||||
private Ordering ordering;
|
||||
private boolean orderingCached = false;
|
||||
private DataType dataType;
|
||||
private Class<?> compositePrimaryKeyType;
|
||||
private CassandraPersistentEntity<?> compositePrimaryKeyEntity;
|
||||
private TypeInformation<?> compositePrimaryKeyTypeInformation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CachingCassandraPersistentProperty}.
|
||||
@@ -52,12 +55,12 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent
|
||||
}
|
||||
|
||||
@Override
|
||||
public CassandraPersistentEntity<?> getCompositePrimaryKeyEntity() {
|
||||
public TypeInformation<?> getCompositePrimaryKeyTypeInformation() {
|
||||
|
||||
if (compositePrimaryKeyEntity == null) {
|
||||
compositePrimaryKeyEntity = super.getCompositePrimaryKeyEntity();
|
||||
if (compositePrimaryKeyTypeInformation == null) {
|
||||
compositePrimaryKeyTypeInformation = super.getCompositePrimaryKeyTypeInformation();
|
||||
}
|
||||
return compositePrimaryKeyEntity;
|
||||
return compositePrimaryKeyTypeInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,4 +153,12 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent
|
||||
}
|
||||
return isPartitionKeyColumn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getColumnNames() {
|
||||
if (columnNames == null) {
|
||||
columnNames = super.getColumnNames();
|
||||
}
|
||||
return columnNames;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* {@link Comparator} implementation that uses {@link Column#value()}.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public enum CassandraColumnAnnotationComparator implements Comparator<Column> {
|
||||
|
||||
/**
|
||||
* The sole instance of this class.
|
||||
*/
|
||||
IT;
|
||||
|
||||
@Override
|
||||
public int compare(Column left, Column right) {
|
||||
return left.value().compareTo(right.value());
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
|
||||
@@ -24,7 +27,15 @@ import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public interface CassandraPersistentEntity<T> extends MutablePersistentEntity<T, CassandraPersistentProperty> {
|
||||
public interface CassandraPersistentEntity<T> extends MutablePersistentEntity<T, CassandraPersistentProperty>,
|
||||
ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Returns whether this entity represents a composite primary key.
|
||||
*/
|
||||
boolean isCompositePrimaryKey();
|
||||
|
||||
List<CassandraPersistentProperty> getCompositePrimaryKeyProperties();
|
||||
|
||||
/**
|
||||
* Returns the table name to which the entity shall be persisted.
|
||||
@@ -37,4 +48,6 @@ public interface CassandraPersistentEntity<T> extends MutablePersistentEntity<T,
|
||||
* @param tableName The table name; must contain a valid Cassandra table name.
|
||||
*/
|
||||
void setTableName(String tableName);
|
||||
|
||||
CassandraMappingContext getMappingContext();
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cassandra.core.Ordering;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
@@ -33,12 +36,6 @@ public interface CassandraPersistentProperty extends PersistentProperty<Cassandr
|
||||
*/
|
||||
boolean isCompositePrimaryKey();
|
||||
|
||||
/**
|
||||
* Returns the type of the composite primary key class of this entity, or null if this class does not use a composite
|
||||
* primary key.
|
||||
*/
|
||||
Class<?> getCompositePrimaryKeyType();
|
||||
|
||||
/**
|
||||
* Returns a {@link CassandraPersistentEntity} representing the composite primary key class of this entity, or null if
|
||||
* this class does not use a composite primary key.
|
||||
@@ -46,22 +43,42 @@ public interface CassandraPersistentProperty extends PersistentProperty<Cassandr
|
||||
CassandraPersistentEntity<?> getCompositePrimaryKeyEntity();
|
||||
|
||||
/**
|
||||
* The name of the column to which a property is persisted.
|
||||
* Returns a {@link TypeInformation} representing the type of the composite primary key class of this entity, or null
|
||||
* if this class does not use a composite primary key.
|
||||
*/
|
||||
TypeInformation<?> getCompositePrimaryKeyTypeInformation();
|
||||
|
||||
/**
|
||||
* Gets the list of composite primary key properties that this composite primary key field is a placeholder for.
|
||||
*/
|
||||
List<CassandraPersistentProperty> getCompositePrimaryKeyProperties();
|
||||
|
||||
/**
|
||||
* The name of the single column to which the property is persisted. This is a convenience method when the caller
|
||||
* knows that the property is mapped to a single column. Throws {@link IllegalStateException} if this property is
|
||||
* mapped to multiple columns.
|
||||
*/
|
||||
String getColumnName();
|
||||
|
||||
/**
|
||||
* The ordering for the column. Valid only for clustered columns.
|
||||
* The names of the columns to which the property is persisted if this is a composite primary key property. Never
|
||||
* returns null.
|
||||
*/
|
||||
List<String> getColumnNames();
|
||||
|
||||
/**
|
||||
* The ordering (ascending or descending) for the column. Valid only for primary key columns; returns null for
|
||||
* non-primary key columns.
|
||||
*/
|
||||
Ordering getPrimaryKeyOrdering();
|
||||
|
||||
/**
|
||||
* The column's data type.
|
||||
* The column's data type. Not valid for a composite primary key, in which case this method returns null.
|
||||
*/
|
||||
DataType getDataType();
|
||||
|
||||
/**
|
||||
* Whether the property has secondary index on this column.
|
||||
* Whether the property has a secondary index on this column.
|
||||
*/
|
||||
boolean isIndexed();
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* {@link Comparator} implementation that orders {@link CassandraPersistentProperty} instances.
|
||||
* <p/>
|
||||
* Composite primary key properties and primary key properties sort before non-primary key properties.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public enum CassandraPersistentPropertyComparator implements Comparator<CassandraPersistentProperty> {
|
||||
|
||||
/**
|
||||
* The sole instance of this class.
|
||||
*/
|
||||
IT;
|
||||
|
||||
@Override
|
||||
public int compare(CassandraPersistentProperty left, CassandraPersistentProperty right) {
|
||||
|
||||
if (left != null && right == null) {
|
||||
return -1;
|
||||
}
|
||||
if (left == null && right != null) {
|
||||
return 1;
|
||||
}
|
||||
if (left == null && right == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (left.equals(right)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean leftIsCompositePrimaryKey = left.isCompositePrimaryKey();
|
||||
boolean rightIsCompositePrimaryKey = right.isCompositePrimaryKey();
|
||||
|
||||
if (leftIsCompositePrimaryKey && rightIsCompositePrimaryKey) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean leftIsPrimaryKey = left.isPrimaryKeyColumn();
|
||||
boolean rightIsPrimaryKey = right.isPrimaryKeyColumn();
|
||||
|
||||
Field leftField = left.getField();
|
||||
Field rightField = right.getField();
|
||||
|
||||
if (leftIsPrimaryKey && rightIsPrimaryKey) {
|
||||
return CassandraPrimaryKeyColumnAnnotationComparator.IT.compare(leftField.getAnnotation(PrimaryKeyColumn.class),
|
||||
rightField.getAnnotation(PrimaryKeyColumn.class));
|
||||
}
|
||||
|
||||
boolean leftIsKey = leftIsCompositePrimaryKey || leftIsPrimaryKey;
|
||||
boolean rightIsKey = rightIsCompositePrimaryKey || rightIsPrimaryKey;
|
||||
|
||||
if (leftIsKey && !rightIsKey) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!leftIsKey && rightIsKey) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// else, neither property is a composite primary key nor a primary key; compare @Column annotations
|
||||
|
||||
Column leftColumn = leftField.getAnnotation(Column.class);
|
||||
Column rightColumn = rightField.getAnnotation(Column.class);
|
||||
|
||||
if (leftColumn == null && rightColumn == null) {
|
||||
return leftField.getName().compareTo(rightField.getName());
|
||||
}
|
||||
|
||||
if (leftColumn != null && rightColumn != null) {
|
||||
return CassandraColumnAnnotationComparator.IT.compare(leftColumn, rightColumn);
|
||||
}
|
||||
|
||||
if (leftColumn != null && rightColumn == null) {
|
||||
return leftColumn.value().compareTo(rightField.getName());
|
||||
}
|
||||
|
||||
// else leftColumn == null && rightColumn != null)
|
||||
return leftField.getName().compareTo(rightColumn.value());
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public enum DefaultCassandraPrimaryKeyColumnComparator implements Comparator<PrimaryKeyColumn> {
|
||||
public enum CassandraPrimaryKeyColumnAnnotationComparator implements Comparator<PrimaryKeyColumn> {
|
||||
|
||||
/**
|
||||
* The sole instance of this class.
|
||||
@@ -27,23 +27,23 @@ public enum DefaultCassandraPrimaryKeyColumnComparator implements Comparator<Pri
|
||||
IT;
|
||||
|
||||
@Override
|
||||
public int compare(PrimaryKeyColumn o1, PrimaryKeyColumn o2) {
|
||||
public int compare(PrimaryKeyColumn left, PrimaryKeyColumn right) {
|
||||
|
||||
int comparison = o1.type().compareTo(o2.type());
|
||||
int comparison = left.type().compareTo(right.type());
|
||||
if (comparison != 0) {
|
||||
return comparison;
|
||||
}
|
||||
|
||||
comparison = new Integer(o1.ordinal()).compareTo(o2.ordinal());
|
||||
comparison = new Integer(left.ordinal()).compareTo(right.ordinal());
|
||||
if (comparison != 0) {
|
||||
return comparison;
|
||||
}
|
||||
|
||||
comparison = o1.name().compareTo(o2.name());
|
||||
comparison = left.name().compareTo(right.name());
|
||||
if (comparison != 0) {
|
||||
return comparison;
|
||||
}
|
||||
|
||||
return o1.ordering().compareTo(o2.ordering());
|
||||
return left.ordering().compareTo(right.ordering());
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import static org.springframework.cassandra.core.keyspace.CreateTableSpecification.createTable;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
@@ -73,7 +75,7 @@ public class DefaultCassandraMappingContext extends
|
||||
@Override
|
||||
protected <T> CassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
|
||||
BasicCassandraPersistentEntity<T> entity = new BasicCassandraPersistentEntity<T>(typeInformation);
|
||||
CassandraPersistentEntity<T> entity = new CachingCassandraPersistentEntity<T>(typeInformation, this);
|
||||
|
||||
if (context != null) {
|
||||
entity.setApplicationContext(context);
|
||||
@@ -104,9 +106,7 @@ public class DefaultCassandraMappingContext extends
|
||||
|
||||
Assert.notNull(entity);
|
||||
|
||||
final CreateTableSpecification spec = new CreateTableSpecification();
|
||||
|
||||
spec.name(entity.getTableName());
|
||||
final CreateTableSpecification spec = createTable().name(entity.getTableName());
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
|
||||
@@ -124,7 +124,7 @@ public class DefaultCassandraMappingContext extends
|
||||
|
||||
if (pkProp.isPartitionKeyColumn()) {
|
||||
spec.partitionKeyColumn(pkProp.getColumnName(), pkProp.getDataType());
|
||||
} else {
|
||||
} else { // it's a cluster column
|
||||
spec.clusteredKeyColumn(pkProp.getColumnName(), pkProp.getDataType(), pkProp.getPrimaryKeyOrdering());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* {@link Comparator} implementation that uses the {@link CassandraPersistentProperty}'s column name for ordering.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public enum DefaultCassandraPersistentPropertyColumnComparator implements Comparator<CassandraPersistentProperty> {
|
||||
|
||||
/**
|
||||
* The sole instance of this class.
|
||||
*/
|
||||
IT;
|
||||
|
||||
@Override
|
||||
public int compare(CassandraPersistentProperty o1, CassandraPersistentProperty o2) {
|
||||
return o1.getColumnName().compareTo(o2.getColumnName());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
package org.springframework.data.cassandra.config;
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mapping information for an individual entity class.
|
||||
@@ -7,9 +10,21 @@ package org.springframework.data.cassandra.config;
|
||||
*/
|
||||
public class EntityMapping {
|
||||
|
||||
/**
|
||||
* The name of the entity's class.
|
||||
*/
|
||||
protected String entityClassName;
|
||||
|
||||
/**
|
||||
* The name of the table to which the entity is mapped.
|
||||
*/
|
||||
protected String tableName;
|
||||
|
||||
/**
|
||||
* The {@link PropertyMapping}s for each persistent property, keyed on property name.
|
||||
*/
|
||||
protected Map<String, PropertyMapping> propertyMappings = new HashMap<String, PropertyMapping>();
|
||||
|
||||
public EntityMapping(String entityClassName, String tableName) {
|
||||
setEntityClassName(entityClassName);
|
||||
setTableName(tableName);
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Mapping between a persistent entity's property and its column.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public class PropertyMapping {
|
||||
|
||||
protected String propertyName;
|
||||
protected String columnName;
|
||||
|
||||
public PropertyMapping(String propertyName, String columnName) {
|
||||
|
||||
setPropertyName(propertyName);
|
||||
setColumnName(columnName);
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
protected void setPropertyName(String propertyName) {
|
||||
Assert.notNull(propertyName);
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
protected void setColumnName(String columnName) {
|
||||
Assert.notNull(columnName);
|
||||
this.columnName = columnName;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.cassandra.repository;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
@@ -24,9 +23,7 @@ import org.springframework.data.repository.CrudRepository;
|
||||
* Cassandra-specific extension of the {@link CrudRepository} interface.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public interface CassandraRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
|
||||
|
||||
List<T> findByPartitionKey(ID id);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,12 +33,4 @@ public interface CassandraEntityInformation<T, ID extends Serializable> extends
|
||||
* @return
|
||||
*/
|
||||
String getTableName();
|
||||
|
||||
/**
|
||||
* Returns the column that the id will be persisted to.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getIdColumn();
|
||||
|
||||
}
|
||||
|
||||
@@ -59,10 +59,6 @@ public class MappingCassandraEntityInformation<T, ID extends Serializable> exten
|
||||
this.customTableName = customTableName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.EntityInformation#getId(java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ID getId(T entity) {
|
||||
@@ -80,28 +76,14 @@ public class MappingCassandraEntityInformation<T, ID extends Serializable> exten
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.EntityInformation#getIdType()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<ID> getIdType() {
|
||||
return (Class<ID>) entityMetadata.getIdProperty().getType();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.CassandraEntityInformation#getTableName()
|
||||
*/
|
||||
@Override
|
||||
public String getTableName() {
|
||||
return customTableName == null ? entityMetadata.getTableName() : customTableName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.CassandraEntityInformation#getIdColumn()
|
||||
*/
|
||||
public String getIdColumn() {
|
||||
return entityMetadata.getIdProperty().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.datastax.driver.core.querybuilder.Clause;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Select.Where;
|
||||
|
||||
/**
|
||||
* Repository base implementation for Cassandra.
|
||||
@@ -41,8 +42,8 @@ import com.datastax.driver.core.querybuilder.Select;
|
||||
|
||||
public class SimpleCassandraRepository<T, ID extends Serializable> implements CassandraRepository<T, ID> {
|
||||
|
||||
private final CassandraTemplate cassandraTemplate;
|
||||
private final CassandraEntityInformation<T, ID> entityInformation;
|
||||
protected final CassandraTemplate cassandraTemplate;
|
||||
protected final CassandraEntityInformation<T, ID> entityInformation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleCassandraRepository} for the given {@link CassandraEntityInformation} and
|
||||
@@ -51,8 +52,7 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param template must not be {@literal null}.
|
||||
*/
|
||||
public SimpleCassandraRepository(CassandraEntityInformation<T, ID> metadata,
|
||||
CassandraTemplate cassandraTemplate) {
|
||||
public SimpleCassandraRepository(CassandraEntityInformation<T, ID> metadata, CassandraTemplate cassandraTemplate) {
|
||||
|
||||
Assert.notNull(cassandraTemplate);
|
||||
Assert.notNull(metadata);
|
||||
@@ -65,6 +65,7 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <S extends T> S save(S entity) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null!");
|
||||
@@ -76,6 +77,7 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
public <S extends T> List<S> save(Iterable<S> entities) {
|
||||
|
||||
Assert.notNull(entities, "The given Iterable of entities not be null!");
|
||||
@@ -90,78 +92,31 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
return result;
|
||||
}
|
||||
|
||||
private Clause getIdClause(ID id) {
|
||||
Clause clause = QueryBuilder.eq(entityInformation.getIdColumn(), id);
|
||||
return clause;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
|
||||
*/
|
||||
public T findOne(ID id) {
|
||||
Assert.notNull(id, "The given id must not be null!");
|
||||
|
||||
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
|
||||
select.where(getIdClause(id));
|
||||
|
||||
return cassandraTemplate.selectOne(select, entityInformation.getJavaType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.repository.CassandraRepository#findByPartitionKey(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public List<T> findByPartitionKey(ID id) {
|
||||
Assert.notNull(id, "The given id must not be null!");
|
||||
|
||||
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
|
||||
select.where(getIdClause(id));
|
||||
|
||||
return cassandraTemplate.select(select, entityInformation.getJavaType());
|
||||
public T findOne(ID id) {
|
||||
return cassandraTemplate.selectOneById(entityInformation.getJavaType(), id);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(ID id) {
|
||||
|
||||
Assert.notNull(id, "The given id must not be null!");
|
||||
|
||||
Select select = QueryBuilder.select().countAll().from(entityInformation.getTableName());
|
||||
select.where(getIdClause(id));
|
||||
|
||||
Long num = cassandraTemplate.count(select);
|
||||
return num != null && num.longValue() > 0;
|
||||
return cassandraTemplate.countById(entityInformation.getJavaType(), id) >= 1; // TODO: == instead of >= ?
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#count()
|
||||
*/
|
||||
@Override
|
||||
public long count() {
|
||||
return cassandraTemplate.count(entityInformation.getTableName());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public void delete(ID id) {
|
||||
Assert.notNull(id, "The given id must not be null!");
|
||||
|
||||
Delete delete = QueryBuilder.delete().all().from(entityInformation.getTableName());
|
||||
delete.where(getIdClause(id));
|
||||
|
||||
cassandraTemplate.execute(delete.getQueryString());
|
||||
cassandraTemplate.deleteById(entityInformation.getJavaType(), id);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void delete(T entity) {
|
||||
Assert.notNull(entity, "The given entity must not be null!");
|
||||
delete(entityInformation.getId(entity));
|
||||
@@ -171,6 +126,7 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
public void delete(Iterable<? extends T> entities) {
|
||||
|
||||
Assert.notNull(entities, "The given Iterable of entities not be null!");
|
||||
@@ -184,6 +140,7 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#deleteAll()
|
||||
*/
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
cassandraTemplate.truncate(entityInformation.getTableName());
|
||||
}
|
||||
@@ -192,29 +149,19 @@ public class SimpleCassandraRepository<T, ID extends Serializable> implements Ca
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll()
|
||||
*/
|
||||
@Override
|
||||
public List<T> findAll() {
|
||||
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
|
||||
return findAll(select);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<T> findAll(Iterable<ID> ids) {
|
||||
|
||||
List<ID> parameters = new ArrayList<ID>();
|
||||
for (ID id : ids) {
|
||||
parameters.add(id);
|
||||
}
|
||||
Clause clause = QueryBuilder.in(entityInformation.getIdColumn(), parameters.toArray());
|
||||
Select select = QueryBuilder.select().all().from(entityInformation.getTableName());
|
||||
select.where(clause);
|
||||
|
||||
return findAll(select);
|
||||
return cassandraTemplate.selectByIds(entityInformation.getJavaType(), ids);
|
||||
}
|
||||
|
||||
private List<T> findAll(Select query) {
|
||||
protected List<T> findAll(Select query) {
|
||||
|
||||
if (query == null) {
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -3,25 +3,14 @@ package org.springframework.data.cassandra.util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cassandra.core.CqlTemplate;
|
||||
import org.springframework.cassandra.core.QueryOptions;
|
||||
import org.springframework.data.cassandra.exception.EntityWriterException;
|
||||
import org.springframework.cassandra.core.cql.CqlStringUtils;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.convert.EntityWriter;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
|
||||
import com.datastax.driver.core.ColumnMetadata;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.Query;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.driver.core.querybuilder.Batch;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Delete.Where;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
|
||||
/**
|
||||
* Utilities to convert Cassandra Annotated objects to Queries and CQL.
|
||||
@@ -33,39 +22,7 @@ import com.datastax.driver.core.querybuilder.Update;
|
||||
public abstract class CqlUtils {
|
||||
|
||||
/**
|
||||
* Create the List of CQL for the indexes required for Cassandra mapped Table.
|
||||
*
|
||||
* @param tableName
|
||||
* @param entity
|
||||
* @return The list of CQL statements to run with session.execute()
|
||||
*/
|
||||
public static List<String> createIndexes(final String tableName, final CassandraPersistentEntity<?> entity) {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
if (prop.isIndexed()) {
|
||||
|
||||
final StringBuilder str = new StringBuilder();
|
||||
str.append("CREATE INDEX ON ");
|
||||
str.append(tableName);
|
||||
str.append(" (");
|
||||
str.append(prop.getColumnName());
|
||||
str.append(");");
|
||||
|
||||
result.add(str.toString());
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the table to refelct the entity annotations
|
||||
* Alter the table to reflect the entity annotations
|
||||
*
|
||||
* @param tableName
|
||||
* @param entity
|
||||
@@ -104,7 +61,7 @@ public abstract class CqlUtils {
|
||||
str.append("TYPE ");
|
||||
}
|
||||
|
||||
str.append(toCQL(columnDataType));
|
||||
str.append(CqlStringUtils.toCql(columnDataType));
|
||||
|
||||
str.append(';');
|
||||
result.add(str.toString());
|
||||
@@ -114,243 +71,4 @@ public abstract class CqlUtils {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Query Object for an insert
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static Query toInsertQuery(String tableName, final Object objectToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) throws EntityWriterException {
|
||||
|
||||
final Insert q = QueryBuilder.insertInto(tableName);
|
||||
|
||||
/*
|
||||
* Write properties
|
||||
*/
|
||||
entityWriter.write(objectToSave, q);
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(q, options);
|
||||
|
||||
/*
|
||||
* Add TTL to Insert object
|
||||
*/
|
||||
if (options != null && options.getTtl() != null) {
|
||||
q.using(QueryBuilder.ttl(options.getTtl()));
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Query Object for an Update
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static Query toUpdateQuery(String tableName, final Object objectToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) throws EntityWriterException {
|
||||
|
||||
final Update q = QueryBuilder.update(tableName);
|
||||
|
||||
/*
|
||||
* Write properties
|
||||
*/
|
||||
entityWriter.write(objectToSave, q);
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(q, options);
|
||||
|
||||
/*
|
||||
* Add TTL to Insert object
|
||||
*/
|
||||
if (options != null && options.getTtl() != null) {
|
||||
q.using(QueryBuilder.ttl(options.getTtl()));
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Batch Object for multiple Updates
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectsToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static <T> Batch toUpdateBatchQuery(final String tableName, final List<T> objectsToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) throws EntityWriterException {
|
||||
|
||||
/*
|
||||
* Return variable is a Batch statement
|
||||
*/
|
||||
final Batch b = QueryBuilder.batch();
|
||||
|
||||
for (final T objectToSave : objectsToSave) {
|
||||
|
||||
b.add((Statement) toUpdateQuery(tableName, objectToSave, options, entityWriter));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(b, options);
|
||||
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Batch Object for multiple inserts
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectsToSave
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static <T> Batch toInsertBatchQuery(final String tableName, final List<T> objectsToSave, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) throws EntityWriterException {
|
||||
|
||||
/*
|
||||
* Return variable is a Batch statement
|
||||
*/
|
||||
final Batch b = QueryBuilder.batch();
|
||||
|
||||
for (final T objectToSave : objectsToSave) {
|
||||
|
||||
b.add((Statement) toInsertQuery(tableName, objectToSave, options, entityWriter));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Add Query Options
|
||||
*/
|
||||
CqlTemplate.addQueryOptions(b, options);
|
||||
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Delete Query Object from an annotated POJO
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectToRemove
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
* @return
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static Query toDeleteQuery(String tableName, final Object objectToRemove, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) throws EntityWriterException {
|
||||
|
||||
final Delete.Selection ds = QueryBuilder.delete();
|
||||
final Delete q = ds.from(tableName);
|
||||
final Where w = q.where();
|
||||
|
||||
/*
|
||||
* Write where condition to find by Id
|
||||
*/
|
||||
entityWriter.write(objectToRemove, w);
|
||||
|
||||
CqlTemplate.addQueryOptions(q, options);
|
||||
|
||||
return q;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static String toCQL(DataType dataType) {
|
||||
if (dataType.getTypeArguments().isEmpty()) {
|
||||
return dataType.getName().name();
|
||||
} else {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(dataType.getName().name());
|
||||
str.append('<');
|
||||
for (DataType argDataType : dataType.getTypeArguments()) {
|
||||
if (str.charAt(str.length() - 1) != '<') {
|
||||
str.append(',');
|
||||
}
|
||||
str.append(argDataType.getName().name());
|
||||
}
|
||||
str.append('>');
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
public static String dropTable(String tableName) {
|
||||
|
||||
if (tableName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append("DROP TABLE " + tableName + ";");
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Batch Query object for multiple deletes.
|
||||
*
|
||||
* @param tableName
|
||||
* @param entities
|
||||
* @param entity
|
||||
* @param optionsByName
|
||||
*
|
||||
* @return
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static <T> Batch toDeleteBatchQuery(String tableName, List<T> entities, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) throws EntityWriterException {
|
||||
|
||||
/*
|
||||
* Return variable is a Batch statement
|
||||
*/
|
||||
final Batch b = QueryBuilder.batch();
|
||||
|
||||
for (final T objectToSave : entities) {
|
||||
|
||||
b.add((Statement) toDeleteQuery(tableName, objectToSave, options, entityWriter));
|
||||
|
||||
}
|
||||
|
||||
CqlTemplate.addQueryOptions(b, options);
|
||||
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.test.integration.mapping;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
import org.springframework.cassandra.core.keyspace.ColumnSpecification;
|
||||
import org.springframework.cassandra.core.keyspace.CreateTableSpecification;
|
||||
import org.springframework.data.cassandra.mapping.BasicCassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.CachingCassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder;
|
||||
import org.springframework.data.cassandra.mapping.Column;
|
||||
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.PrimaryKey;
|
||||
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
|
||||
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Integration test for {@link BasicCassandraPersistentProperty} with a composite primary key class.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public class CassandraCompositePrimaryKeyIntegrationTests {
|
||||
|
||||
private static final CassandraSimpleTypeHolder SIMPLE_TYPE_HOLDER = new CassandraSimpleTypeHolder();
|
||||
|
||||
@PrimaryKeyClass
|
||||
static class Key {
|
||||
|
||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
|
||||
String z;
|
||||
|
||||
@PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED)
|
||||
String a;
|
||||
}
|
||||
|
||||
@Table
|
||||
static class Thing {
|
||||
|
||||
@PrimaryKey
|
||||
Key id;
|
||||
|
||||
Date time;
|
||||
|
||||
@Column("message")
|
||||
String text;
|
||||
}
|
||||
|
||||
CassandraMappingContext context;
|
||||
CassandraPersistentEntity<?> thing;
|
||||
CassandraPersistentEntity<?> key;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
context = new DefaultCassandraMappingContext();
|
||||
thing = context.getPersistentEntity(ClassTypeInformation.from(Thing.class));
|
||||
key = context.getPersistentEntity(ClassTypeInformation.from(Key.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateMappingInfo() {
|
||||
|
||||
Field field = ReflectionUtils.findField(Thing.class, "id");
|
||||
CassandraPersistentProperty property = new CachingCassandraPersistentProperty(field, null, thing,
|
||||
SIMPLE_TYPE_HOLDER);
|
||||
assertTrue(property.isIdProperty());
|
||||
assertTrue(property.isCompositePrimaryKey());
|
||||
|
||||
List<String> expectedColumnNames = Arrays.asList(new String[] { "z", "a" });
|
||||
assertTrue(expectedColumnNames.equals(property.getColumnNames()));
|
||||
|
||||
List<String> actualColumnNames = new ArrayList<String>();
|
||||
List<CassandraPersistentProperty> properties = property.getCompositePrimaryKeyProperties();
|
||||
for (CassandraPersistentProperty p : properties) {
|
||||
actualColumnNames.addAll(p.getColumnNames());
|
||||
}
|
||||
assertTrue(expectedColumnNames.equals(actualColumnNames));
|
||||
|
||||
CreateTableSpecification spec = context.getCreateTableSpecificationFor(thing);
|
||||
|
||||
List<ColumnSpecification> partitionKeyColumns = spec.getPartitionKeyColumns();
|
||||
assertEquals(1, partitionKeyColumns.size());
|
||||
ColumnSpecification partitionKeyColumn = partitionKeyColumns.get(0);
|
||||
assertEquals("z", partitionKeyColumn.getName());
|
||||
assertEquals(PrimaryKeyType.PARTITIONED, partitionKeyColumn.getKeyType());
|
||||
assertEquals(DataType.text(), partitionKeyColumn.getType());
|
||||
|
||||
List<ColumnSpecification> clusteredKeyColumns = spec.getClusteredKeyColumns();
|
||||
assertEquals(1, clusteredKeyColumns.size());
|
||||
ColumnSpecification clusteredKeyColumn = clusteredKeyColumns.get(0);
|
||||
assertEquals("a", clusteredKeyColumn.getName());
|
||||
assertEquals(PrimaryKeyType.CLUSTERED, clusteredKeyColumn.getKeyType());
|
||||
assertEquals(DataType.text(), partitionKeyColumn.getType());
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.cassandra.mapping.BasicCassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.BasicCassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.CachingCassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder;
|
||||
@@ -76,6 +77,6 @@ public class CompoundPrimaryKeyIntegrationTests {
|
||||
}
|
||||
|
||||
private CassandraPersistentProperty getPropertyFor(Field field) {
|
||||
return new BasicCassandraPersistentProperty(field, null, entity, new CassandraSimpleTypeHolder());
|
||||
return new CachingCassandraPersistentProperty(field, null, entity, new CassandraSimpleTypeHolder());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user