Added basic select methods to TemplateAPI

This commit is contained in:
dwebb
2013-11-18 16:00:38 -05:00
parent 6bb16353fd
commit 3ff3e169de
5 changed files with 174 additions and 84 deletions

View File

@@ -22,9 +22,11 @@ import org.springframework.data.cassandra.convert.CassandraConverter;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.querybuilder.Select;
/**
* Main Inteface that should be used for Cassandra interactions
* Operations for interacting with Cassandra. These operations are used by the Repository implementation, but can also
* be used directly when that is desired by the developer.
*
* @author Alex Shvid
* @author David Webb
@@ -70,7 +72,7 @@ public interface CassandraOperations {
* @param selectClass must not be {@literal null}, mapped entity type.
* @return
*/
<T> List<T> select(String query, Class<T> selectClass);
<T> List<T> selectByCQL(String query, Class<T> selectClass);
/**
* Execute query and convert ResultSet to the entity
@@ -79,7 +81,11 @@ public interface CassandraOperations {
* @param selectClass must not be {@literal null}, mapped entity type.
* @return
*/
<T> T selectOne(String query, Class<T> selectClass);
<T> T selectOneByCQL(String query, Class<T> selectClass);
<T> List<T> select(Select selectQuery, Class<T> selectClass);
<T> T selectOne(Select selectQuery, Class<T> selectClass);
/**
* Insert the given object to the table by id.

View File

@@ -32,12 +32,10 @@ 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.core.exceptions.CassandraConnectionFailureException;
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;
import org.springframework.data.convert.EntityReader;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
@@ -48,8 +46,8 @@ import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
import com.datastax.driver.core.querybuilder.Batch;
import com.datastax.driver.core.querybuilder.Select;
/**
* The Cassandra Template is a convenience API for all Cassnadra DML Operations.
@@ -59,31 +57,6 @@ import com.datastax.driver.core.querybuilder.Batch;
*/
public class CassandraTemplate implements CassandraOperations {
/**
* Simple {@link RowCallback} that will transform {@link Row} into the given target type using the given
* {@link EntityReader}.
*
* @author Alex Shvid
*/
private static class ReadRowCallback<T> implements RowCallback<T> {
private final EntityReader<? super T, Object> reader;
private final Class<T> type;
public ReadRowCallback(EntityReader<? super T, Object> reader, Class<T> type) {
Assert.notNull(reader);
Assert.notNull(type);
this.reader = reader;
this.type = type;
}
@Override
public T doWith(Row row) {
T source = reader.read(type, row);
return source;
}
}
private static Logger log = LoggerFactory.getLogger(CassandraTemplate.class);
public static final Collection<String> ITERABLE_CLASSES;
@@ -700,20 +673,36 @@ public class CassandraTemplate implements CassandraOperations {
return insertAsynchronously(entity, tableName, options.toMap());
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#select(com.datastax.driver.core.querybuilder.Select, java.lang.Class)
*/
@Override
public <T> List<T> select(Select selectQuery, Class<T> selectClass) {
return selectByCQL(selectQuery.getQueryString(), selectClass);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#select(java.lang.String, java.lang.Class)
*/
@Override
public <T> List<T> select(String query, Class<T> selectClass) {
return selectInternal(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
public <T> List<T> selectByCQL(String query, Class<T> selectClass) {
return doSelect(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(com.datastax.driver.core.querybuilder.Select, java.lang.Class)
*/
@Override
public <T> T selectOne(Select selectQuery, Class<T> selectClass) {
return selectOneByCQL(selectQuery.getQueryString(), selectClass);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(java.lang.String, java.lang.Class)
*/
@Override
public <T> T selectOne(String query, Class<T> selectClass) {
return selectOneInternal(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
public <T> T selectOneByCQL(String query, Class<T> selectClass) {
return doSelectOne(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
}
/* (non-Javadoc)
@@ -958,6 +947,70 @@ public class CassandraTemplate implements CassandraOperations {
return null;
}
/**
* @param query
* @param readRowCallback
* @return
*/
private <T> List<T> doSelect(final String query, ReadRowCallback<T> readRowCallback) {
ResultSet resultSet = execute(new SessionCallback<ResultSet>() {
@Override
public ResultSet doInSession(Session s) throws DataAccessException {
return s.execute(query);
}
});
if (resultSet == null) {
return null;
}
List<T> result = new ArrayList<T>();
Iterator<Row> iterator = resultSet.iterator();
while (iterator.hasNext()) {
Row row = iterator.next();
result.add(readRowCallback.doWith(row));
}
return result;
}
/**
* @param query
* @param readRowCallback
* @return
*/
private <T> T doSelectOne(final String query, ReadRowCallback<T> readRowCallback) {
/*
* Run the Query
*/
ResultSet resultSet = execute(new SessionCallback<ResultSet>() {
@Override
public ResultSet doInSession(Session s) throws DataAccessException {
return s.execute(query);
}
});
if (resultSet == null) {
return null;
}
Iterator<Row> iterator = resultSet.iterator();
if (iterator.hasNext()) {
Row row = iterator.next();
T result = readRowCallback.doWith(row);
if (iterator.hasNext()) {
throw new DuplicateKeyException("found two or more results in query " + query);
}
return result;
}
return null;
}
private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex) {
RuntimeException resolved = this.exceptionTranslator.translateExceptionIfPossible(ex);
return resolved == null ? ex : resolved;
@@ -1240,51 +1293,4 @@ 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);
List<T> result = new ArrayList<T>();
Iterator<Row> iterator = resultSet.iterator();
while (iterator.hasNext()) {
Row row = iterator.next();
result.add(readRowCallback.doWith(row));
}
return result;
} catch (NoHostAvailableException e) {
throw new CassandraConnectionFailureException(null, "no host available", e);
} catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e);
}
}
/**
* @param query
* @param readRowCallback
* @return
*/
<T> T selectOneInternal(String query, ReadRowCallback<T> readRowCallback) {
try {
ResultSet resultSet = session.execute(query);
Iterator<Row> iterator = resultSet.iterator();
if (iterator.hasNext()) {
Row row = iterator.next();
T result = readRowCallback.doWith(row);
if (iterator.hasNext()) {
throw new DuplicateKeyException("found two or more results in query " + query);
}
return result;
}
return null;
} catch (NoHostAvailableException e) {
throw new CassandraConnectionFailureException(null, "no host available", e);
} catch (RuntimeException e) {
throw potentiallyConvertRuntimeException(e);
}
}
}

View File

@@ -19,7 +19,7 @@ import java.util.HashMap;
import java.util.Map;
/**
* Contains Query Options for Cassnadra queries. This controls the Consistency Tuning and Retry Policy for a Query.
* Contains Query Options for Cassandra queries. This controls the Consistency Tuning and Retry Policy for a Query.
*
* @author David Webb
*

View File

@@ -0,0 +1,46 @@
/*
* 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.core;
import org.springframework.data.convert.EntityReader;
import org.springframework.util.Assert;
import com.datastax.driver.core.Row;
/**
* Simple {@link RowCallback} that will transform {@link Row} into the given target type using the given
* {@link EntityReader}.
*
* @author Alex Shvid
*/
public class ReadRowCallback<T> implements RowCallback<T> {
private final EntityReader<? super T, Object> reader;
private final Class<T> type;
public ReadRowCallback(EntityReader<? super T, Object> reader, Class<T> type) {
Assert.notNull(reader);
Assert.notNull(type);
this.reader = reader;
this.type = type;
}
@Override
public T doWith(Row row) {
T source = reader.read(type, row);
return source;
}
}

View File

@@ -24,6 +24,8 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import junit.framework.Assert;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.thrift.transport.TTransportException;
import org.cassandraunit.CassandraCQLUnit;
@@ -51,8 +53,11 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
/**
* Unit Tests for CassnadraTemplate
* Unit Tests for CassandraTemplate
*
* @author David Webb
*
@@ -880,6 +885,33 @@ public class CassandraOperationsTest {
}
@Test
public void selectTest() {
/*
* Test Single Insert with entity
*/
Book b1 = new Book();
b1.setIsbn("123456-1");
b1.setTitle("Spring Data Cassandra Guide");
b1.setAuthor("Cassandra Guru");
b1.setPages(521);
cassandraTemplate.insert(b1);
Select select = QueryBuilder.select().all().from("book");
select.where(QueryBuilder.eq("isbn", "123456-1"));
Book b = cassandraTemplate.selectOne(select, Book.class);
log.info("SingleSelect Book Title -> " + b.getTitle());
log.info("SingleSelect Book Author -> " + b.getAuthor());
Assert.assertEquals(b.getTitle(), "Spring Data Cassandra Guide");
Assert.assertEquals(b.getAuthor(), "Cassandra Guru");
}
@After
public void clearCassandra() {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();