From 3cb6639e05256e21957074a4ef81e282f07632b4 Mon Sep 17 00:00:00 2001 From: dwebb Date: Thu, 14 Nov 2013 15:37:50 -0500 Subject: [PATCH] wip: Finished Implementation of update methods. --- .../cassandra/core/CassandraOperations.java | 4 +- .../cassandra/core/CassandraTemplate.java | 168 ++++++++++++++---- .../data/cassandra/util/CqlUtils.java | 107 +++++++++++ 3 files changed, 242 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java b/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java index d9035f1cd..2b463fb16 100644 --- a/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java +++ b/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java @@ -24,9 +24,9 @@ import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSetFuture; /** + * Main Inteface that should be used for Cassandra interactions + * * @author Alex Shvid - */ -/** * @author David Webb * */ diff --git a/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index 0015d51b4..2d3ada4c9 100644 --- a/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -208,6 +208,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void deleteAsychronously(List entities, String tableName) { + insertAsynchronously(entities, tableName, new HashMap()); } /* (non-Javadoc) @@ -227,8 +228,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public void deleteAsychronously(List entities, String tableName, QueryOptions options) { - // TODO Auto-generated method stub - + deleteAsychronously(entities, tableName, options.toMap()); } /* (non-Javadoc) @@ -571,8 +571,9 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List update(List entities) { - // TODO Auto-generated method stub - return null; + String tableName = getTableName(entities.get(0).getClass()); + Assert.notNull(tableName); + return update(entities, tableName); } /* (non-Javadoc) @@ -580,8 +581,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List update(List entities, String tableName) { - // TODO Auto-generated method stub - return null; + return update(entities, tableName, new HashMap()); } /* (non-Javadoc) @@ -589,8 +589,11 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List update(List entities, String tableName, Map optionsByName) { - // TODO Auto-generated method stub - return null; + Assert.notNull(entities); + Assert.notEmpty(entities); + Assert.notNull(tableName); + Assert.notNull(optionsByName); + return doBatchUpdate(tableName, entities, optionsByName, false); } /* (non-Javadoc) @@ -598,8 +601,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List update(List entities, String tableName, QueryOptions options) { - // TODO Auto-generated method stub - return null; + return update(entities, tableName, options.toMap()); } /* (non-Javadoc) @@ -607,8 +609,9 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T update(T entity) { - // TODO Auto-generated method stub - return null; + String tableName = getTableName(entity.getClass()); + Assert.notNull(tableName); + return update(entity, tableName); } /* (non-Javadoc) @@ -616,8 +619,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T update(T entity, String tableName) { - // TODO Auto-generated method stub - return null; + return update(entity, tableName, new HashMap()); } /* (non-Javadoc) @@ -625,8 +627,10 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T update(T entity, String tableName, Map optionsByName) { - // TODO Auto-generated method stub - return null; + Assert.notNull(entity); + Assert.notNull(tableName); + Assert.notNull(optionsByName); + return doUpdate(tableName, entity, optionsByName, false); } /* (non-Javadoc) @@ -634,8 +638,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T update(T entity, String tableName, QueryOptions options) { - // TODO Auto-generated method stub - return null; + return update(entity, tableName, options.toMap()); } /* (non-Javadoc) @@ -643,8 +646,9 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List updateAsynchronously(List entities) { - // TODO Auto-generated method stub - return null; + String tableName = getTableName(entities.get(0).getClass()); + Assert.notNull(tableName); + return updateAsynchronously(entities, tableName); } /* (non-Javadoc) @@ -652,8 +656,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List updateAsynchronously(List entities, String tableName) { - // TODO Auto-generated method stub - return null; + return updateAsynchronously(entities, tableName, new HashMap()); } /* (non-Javadoc) @@ -661,8 +664,11 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List updateAsynchronously(List entities, String tableName, Map optionsByName) { - // TODO Auto-generated method stub - return null; + Assert.notNull(entities); + Assert.notEmpty(entities); + Assert.notNull(tableName); + Assert.notNull(optionsByName); + return doBatchUpdate(tableName, entities, optionsByName, true); } /* (non-Javadoc) @@ -670,8 +676,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public List updateAsynchronously(List entities, String tableName, QueryOptions options) { - // TODO Auto-generated method stub - return null; + return updateAsynchronously(entities, tableName, options.toMap()); } /* (non-Javadoc) @@ -679,8 +684,9 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T updateAsynchronously(T entity) { - // TODO Auto-generated method stub - return null; + String tableName = getTableName(entity.getClass()); + Assert.notNull(tableName); + return updateAsynchronously(entity, tableName); } /* (non-Javadoc) @@ -688,8 +694,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T updateAsynchronously(T entity, String tableName) { - // TODO Auto-generated method stub - return null; + return updateAsynchronously(entity, tableName, new HashMap()); } /* (non-Javadoc) @@ -697,8 +702,10 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T updateAsynchronously(T entity, String tableName, Map optionsByName) { - // TODO Auto-generated method stub - return null; + Assert.notNull(entity); + Assert.notNull(tableName); + Assert.notNull(optionsByName); + return doUpdate(tableName, entity, optionsByName, true); } /* (non-Javadoc) @@ -706,8 +713,7 @@ public class CassandraTemplate implements CassandraOperations { */ @Override public T updateAsynchronously(T entity, String tableName, QueryOptions options) { - // TODO Auto-generated method stub - return null; + return updateAsynchronously(entity, tableName, options.toMap()); } /** @@ -773,7 +779,10 @@ public class CassandraTemplate implements CassandraOperations { * Insert a row into a Cassandra CQL Table * * @param tableName - * @param entity + * @param entities + * @param optionsByName + * @param insertAsychronously + * @return */ protected List doBatchInsert(final String tableName, final List entities, Map optionsByName, final boolean insertAsychronously) { @@ -811,6 +820,51 @@ public class CassandraTemplate implements CassandraOperations { } } + /** + * Update a Batch of rows in a Cassandra CQL Table + * + * @param tableName + * @param entities + * @param optionsByName + * @param updateAsychronously + * @return + */ + protected List doBatchUpdate(final String tableName, final List entities, + Map optionsByName, final boolean updateAsychronously) { + + Assert.notEmpty(entities); + + CassandraPersistentEntity CPEntity = getEntity(entities.get(0)); + + Assert.notNull(CPEntity); + + try { + + final Batch b = CqlUtils.toUpdateBatchQuery(keyspace.getKeyspace(), tableName, entities, CPEntity, optionsByName); + log.info(b.toString()); + + return execute(new SessionCallback>() { + + @Override + public List doInSession(Session s) throws DataAccessException { + + if (updateAsychronously) { + s.executeAsync(b); + } else { + s.execute(b); + } + + return entities; + + } + }); + + } catch (EntityWriterException e) { + throw exceptionTranslator.translateExceptionIfPossible(new RuntimeException( + "Failed to translate Object to Query", e)); + } + } + /** * Perform the removal of a Row. * @@ -892,6 +946,50 @@ public class CassandraTemplate implements CassandraOperations { } + /** + * Update a row into a Cassandra CQL Table + * + * @param tableName + * @param entity + * @param optionsByName + * @param updateAsychronously + * @return + */ + protected T doUpdate(final String tableName, final T entity, final Map optionsByName, + final boolean updateAsychronously) { + + CassandraPersistentEntity CPEntity = getEntity(entity); + + Assert.notNull(CPEntity); + + try { + + final Query q = CqlUtils.toUpdateQuery(keyspace.getKeyspace(), tableName, entity, CPEntity, optionsByName); + log.info(q.toString()); + + return execute(new SessionCallback() { + + @Override + public T doInSession(Session s) throws DataAccessException { + + if (updateAsychronously) { + s.executeAsync(q); + } else { + s.execute(q); + } + + return entity; + + } + }); + + } catch (EntityWriterException e) { + throw exceptionTranslator.translateExceptionIfPossible(new RuntimeException( + "Failed to translate Object to Query", e)); + } + + } + /** * Verify the object is not an iterable type * diff --git a/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java b/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java index 65fc10a1f..5d333912c 100644 --- a/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java +++ b/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java @@ -27,6 +27,7 @@ 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; /** * @@ -263,6 +264,112 @@ public abstract class CqlUtils { } + /** + * Generates a Query Object for an Update + * + * @param keyspaceName + * @param tableName + * @param entity + * @param objectToSave + * @param optionsByName + * @param mappingContext + * @param beanClassLoader + * + * @return The Query object to run with session.execute(); + * @throws EntityWriterException + */ + public static Query toUpdateQuery(String keyspaceName, String tableName, final Object objectToSave, + CassandraPersistentEntity entity, Map optionsByName) throws EntityWriterException { + + final Update q = QueryBuilder.update(keyspaceName, tableName); + final Exception innerException = new Exception(); + + entity.doWithProperties(new PropertyHandler() { + public void doWithPersistentProperty(CassandraPersistentProperty prop) { + + /* + * See if the object has a value for that column, and if so, add it to the Query + */ + try { + + Object o = prop.getGetter().invoke(objectToSave, new Object[0]); + + log.info("Getter Invoke [" + prop.getColumnName() + " => " + o); + + if (o != null) { + if (prop.isIdProperty()) { + q.where(QueryBuilder.eq(prop.getColumnName(), o)); + } else { + q.with(QueryBuilder.add(prop.getColumnName(), o)); + } + } + + } catch (IllegalAccessException e) { + innerException.initCause(e); + } catch (IllegalArgumentException e) { + innerException.initCause(e); + } catch (InvocationTargetException e) { + innerException.initCause(e); + } + } + }); + + if (innerException.getCause() != null) { + throw new EntityWriterException("Failed to convert Persistent Entity to CQL/Query", innerException.getCause()); + } + + /* + * Add Query Options + */ + addQueryOptions(q, optionsByName); + + /* + * Add TTL to Insert object + */ + if (optionsByName.get(QueryOptions.QueryOptionMapKeys.TTL) != null) { + q.using(QueryBuilder.ttl((Integer) optionsByName.get(QueryOptions.QueryOptionMapKeys.TTL))); + } + + return q; + + } + + /** + * Generates a Batch Object for multiple Updates + * + * @param keyspaceName + * @param tableName + * @param entity + * @param objectsToSave + * @param mappingContext + * @param beanClassLoader + * + * @return The Query object to run with session.execute(); + * @throws EntityWriterException + */ + public static Batch toUpdateBatchQuery(final String keyspaceName, final String tableName, + final List objectsToSave, CassandraPersistentEntity entity, Map optionsByName) + throws EntityWriterException { + + /* + * Return variable is a Batch statement + */ + final Batch b = QueryBuilder.batch(); + + List queries = new ArrayList(); + + for (final T objectToSave : objectsToSave) { + + queries.add(toUpdateQuery(keyspaceName, tableName, objectToSave, entity, optionsByName)); + + } + + addQueryOptions(b, optionsByName); + + return b; + + } + /** * Generates a Batch Object for multiple inserts *