IN PROGRESS - issue DATACASS-32: Implement the TemplateAPI for CQL
https://jira.springsource.org/browse/DATACASS-32 Completed the insert and fixed issue with select() and selectOne().
This commit is contained in:
@@ -67,6 +67,16 @@ public class CassandraPropertyValueProvider implements PropertyValueProvider<Cas
|
||||
return null;
|
||||
}
|
||||
DataType columnType = source.getColumnDefinitions().getType(columnName);
|
||||
|
||||
/*
|
||||
* Dave Webb - Added handler for text since getBytes was throwing
|
||||
* InvalidTypeException when using getBytes on a text column.
|
||||
*/
|
||||
//TODO Might need to qualify all DataTypes as we encounter them.
|
||||
if (columnType.equals(DataType.text())) {
|
||||
return (T) source.getString(columnName);
|
||||
}
|
||||
|
||||
ByteBuffer bytes = source.getBytes(columnName);
|
||||
return (T) columnType.deserialize(bytes);
|
||||
}
|
||||
|
||||
@@ -133,13 +133,25 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
|
||||
return result;
|
||||
}
|
||||
|
||||
public void write(Object source, Row sink) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
|
||||
this.useFieldAccessOnly = useFieldAccessOnly;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.EntityWriter#write(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void write(Object source, Row sink) {
|
||||
|
||||
/*
|
||||
* There is no concept of passing a Row into Cassandra for Writing.
|
||||
* This must be done with Query
|
||||
*
|
||||
* See the CQLUtils.
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.exception.EntityWriterException;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.util.CQLUtils;
|
||||
@@ -142,11 +143,39 @@ public class CassandraTemplate implements CassandraOperations {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the PersistentEntityType for a given Object
|
||||
*
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
protected CassandraPersistentEntity<?> getEntity(Object o) {
|
||||
|
||||
CassandraPersistentEntity<?> entity = null;
|
||||
|
||||
try {
|
||||
String entityClassName = o.getClass().getName();
|
||||
Class<?> entityClass = ClassUtils.forName(entityClassName, this.beanClassLoader);
|
||||
entity = mappingContext.getPersistentEntity(entityClass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (LinkageError e) {
|
||||
e.printStackTrace();
|
||||
} finally {}
|
||||
|
||||
return entity;
|
||||
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#getTableName(java.lang.Class)
|
||||
*/
|
||||
public String getTableName(Class<?> entityClass) {
|
||||
return determineTableName(entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#executeQuery(java.lang.String)
|
||||
*/
|
||||
public ResultSet executeQuery(String query) {
|
||||
try {
|
||||
return session.execute(query);
|
||||
@@ -157,31 +186,27 @@ public class CassandraTemplate implements CassandraOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#select(java.lang.String, java.lang.Class)
|
||||
*/
|
||||
public <T> List<T> select(String query, Class<T> selectClass) {
|
||||
return selectInternal(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(java.lang.String, java.lang.Class)
|
||||
*/
|
||||
public <T> T selectOne(String query, Class<T> selectClass) {
|
||||
return selectOneInternal(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#getConverter()
|
||||
*/
|
||||
public CassandraConverter getConverter() {
|
||||
return cassandraConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple internal callback to allow operations on a {@link Row}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
private interface RowCallback<T> {
|
||||
|
||||
T doWith(Row object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link RowCallback} that will transform {@link Row} into the given target type using the given
|
||||
* {@link EntityReader}.
|
||||
@@ -206,6 +231,11 @@ public class CassandraTemplate implements CassandraOperations {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param query
|
||||
* @param readRowCallback
|
||||
* @return
|
||||
*/
|
||||
<T> List<T> selectInternal(String query, ReadRowCallback<T> readRowCallback) {
|
||||
try {
|
||||
ResultSet resultSet = session.execute(query);
|
||||
@@ -281,43 +311,37 @@ public class CassandraTemplate implements CassandraOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a row into a Cassandra ColumnFamily
|
||||
* Insert a row into a Cassandra CQL Table
|
||||
*
|
||||
* @param tableName
|
||||
* @param objectToSave
|
||||
* @throws LinkageError
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
protected <T> T doInsert(final String tableName, final T objectToSave) {
|
||||
|
||||
CassandraPersistentEntity<?> entity = getEntity(objectToSave);
|
||||
|
||||
Assert.notNull(entity);
|
||||
|
||||
try {
|
||||
|
||||
final String entityClassName = objectToSave.getClass().getName();
|
||||
final Class<?> entityClass = ClassUtils.forName(entityClassName, this.beanClassLoader);
|
||||
final CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
final String useTableName = tableName != null ? tableName : entity.getTable();
|
||||
final Query q = CQLUtils.toInsertQuery(keyspace.getKeyspace(), tableName, objectToSave, entity);
|
||||
log.info(q.toString());
|
||||
|
||||
return execute(new SessionCallback<T>() {
|
||||
|
||||
public T doInSession(Session s) throws DataAccessException {
|
||||
|
||||
s.execute(q);
|
||||
|
||||
Query q = CQLUtils.toInsertQuery(keyspace.getKeyspace(), useTableName, entity, objectToSave);
|
||||
log.info(q.toString());
|
||||
|
||||
ResultSet rs = s.execute(q);
|
||||
|
||||
return null;
|
||||
return objectToSave;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (LinkageError e) {
|
||||
e.printStackTrace();
|
||||
} finally {}
|
||||
|
||||
return objectToSave;
|
||||
} catch (EntityWriterException e) {
|
||||
throw exceptionTranslator.translateExceptionIfPossible(new RuntimeException("Failed to translate Object to Query", e));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* All BrightMove Code is Copyright 2004-2013 BrightMove Inc.
|
||||
* Modification of code without the express written consent of
|
||||
* BrightMove, Inc. is strictly forbidden.
|
||||
*
|
||||
* Author: David Webb (dwebb@brightmove.com)
|
||||
* Created On: Nov 12, 2013
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* Simple internal callback to allow operations on a {@link Row}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public interface RowCallback<T> {
|
||||
|
||||
T doWith(Row object);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* All BrightMove Code is Copyright 2004-2013 BrightMove Inc.
|
||||
* Modification of code without the express written consent of
|
||||
* BrightMove, Inc. is strictly forbidden.
|
||||
*
|
||||
* Author: David Webb (dwebb@brightmove.com)
|
||||
* Created On: Nov 12, 2013
|
||||
*/
|
||||
package org.springframework.data.cassandra.exception;
|
||||
|
||||
/**
|
||||
* Exception to handle failing to write a PersistedEntity to a CQL String or Query object
|
||||
*
|
||||
* @author David Webb (dwebb@brightmove.com)
|
||||
*
|
||||
*/
|
||||
public class EntityWriterException extends Exception {
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,9 +7,12 @@ import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.cassandra.exception.EntityWriterException;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.ColumnMetadata;
|
||||
import com.datastax.driver.core.DataType;
|
||||
@@ -31,6 +34,13 @@ public abstract class CQLUtils {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(CQLUtils.class);
|
||||
|
||||
/**
|
||||
* Generates the CQL String to create a table in Cassandra
|
||||
*
|
||||
* @param tableName
|
||||
* @param entity
|
||||
* @return The CQL that can be passed to session.execute()
|
||||
*/
|
||||
public static String createTable(String tableName, final CassandraPersistentEntity<?> entity) {
|
||||
|
||||
final StringBuilder str = new StringBuilder();
|
||||
@@ -101,6 +111,13 @@ public abstract class CQLUtils {
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>();
|
||||
|
||||
@@ -126,6 +143,14 @@ public abstract class CQLUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the table to refelct the entity annotations
|
||||
*
|
||||
* @param tableName
|
||||
* @param entity
|
||||
* @param table
|
||||
* @return
|
||||
*/
|
||||
public static List<String> alterTable(final String tableName, final CassandraPersistentEntity<?> entity, final TableMetadata table) {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
|
||||
@@ -171,9 +196,24 @@ public abstract class CQLUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Query toInsertQuery(String keyspaceName, String tableName, final CassandraPersistentEntity<?> entity, final Object objectToSave) {
|
||||
/**
|
||||
* Generates a Query Object for an insert
|
||||
*
|
||||
* @param keyspaceName
|
||||
* @param tableName
|
||||
* @param entity
|
||||
* @param objectToSave
|
||||
* @param mappingContext
|
||||
* @param beanClassLoader
|
||||
*
|
||||
* @return The Query object to run with session.execute();
|
||||
* @throws EntityWriterException
|
||||
*/
|
||||
public static Query toInsertQuery(String keyspaceName, String tableName,
|
||||
final Object objectToSave, CassandraPersistentEntity<?> entity) throws EntityWriterException {
|
||||
|
||||
final Insert q = QueryBuilder.insertInto(keyspaceName, tableName);
|
||||
final Exception innerException = new Exception();
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
@@ -191,15 +231,19 @@ public abstract class CQLUtils {
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
innerException.initCause(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
innerException.initCause(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
innerException.initCause(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (innerException.getCause() != null) {
|
||||
throw new EntityWriterException("Failed to convert Persistent Entity to CQL/Query", innerException.getCause());
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
}
|
||||
|
||||
@@ -89,8 +89,17 @@ public class CassandraOperationsTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test inserts and selects users from the test.users table
|
||||
* This is testing the CassandraTemplate:
|
||||
* <ul>
|
||||
* <li>insert()</li>
|
||||
* <li>selectOne()</li>
|
||||
* <li>select()</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void insertTest() {
|
||||
public void UsersTest() {
|
||||
|
||||
User u = new User();
|
||||
u.setUsername("cassandra");
|
||||
@@ -99,6 +108,20 @@ public class CassandraOperationsTest {
|
||||
|
||||
cassandraTemplate.insert(u, "users");
|
||||
|
||||
User us = cassandraTemplate.selectOne("select * from test.users where username='cassandra';" , User.class);
|
||||
|
||||
log.debug("Output from select One");
|
||||
log.debug(us.getFirstName());
|
||||
log.debug(us.getLastName());
|
||||
|
||||
List<User> users = cassandraTemplate.select("Select * from test.users", User.class);
|
||||
|
||||
log.debug("Output from select All");
|
||||
for (User x: users) {
|
||||
log.debug(x.getFirstName());
|
||||
log.debug(x.getLastName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
Reference in New Issue
Block a user