org.springframework.data.cassandra.core.CassandraTemplate Maven / Gradle / Ivy
Show all versions of spring-data-cassandra Show documentation
/*
* Copyright 2016-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.core;
import lombok.Value;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.dao.DataAccessException;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.convert.QueryMapper;
import org.springframework.data.cassandra.core.convert.UpdateMapper;
import org.springframework.data.cassandra.core.cql.CassandraAccessor;
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
import org.springframework.data.cassandra.core.cql.CqlOperations;
import org.springframework.data.cassandra.core.cql.CqlProvider;
import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.data.cassandra.core.cql.QueryOptions;
import org.springframework.data.cassandra.core.cql.SessionCallback;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.core.mapping.event.AfterConvertEvent;
import org.springframework.data.cassandra.core.mapping.event.AfterDeleteEvent;
import org.springframework.data.cassandra.core.mapping.event.AfterLoadEvent;
import org.springframework.data.cassandra.core.mapping.event.AfterSaveEvent;
import org.springframework.data.cassandra.core.mapping.event.BeforeDeleteEvent;
import org.springframework.data.cassandra.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.domain.Slice;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import com.datastax.driver.core.RegularStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.exceptions.DriverException;
import com.datastax.driver.core.querybuilder.Delete;
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.Truncate;
import com.datastax.driver.core.querybuilder.Update;
/**
* Primary implementation of {@link CassandraOperations}. It simplifies the use of Cassandra usage and helps to avoid
* common errors. It executes core Cassandra workflow. This class executes CQL queries or updates, initiating iteration
* over {@link ResultSet} and catching Cassandra exceptions and translating them to the generic, more informative
* exception hierarchy defined in the {@code org.springframework.dao} package.
*
* Can be used within a service implementation via direct instantiation with a {@link Session} reference, or get
* prepared in an application context and given to services as bean reference.
*
* Note: The {@link Session} should always be configured as a bean in the application context, in the first case given
* to the service directly, in the second case to the prepared template.
*
* @author Mark Paluch
* @author John Blum
* @author Lukasz Antoniak
* @see org.springframework.data.cassandra.core.CassandraOperations
* @since 2.0
*/
public class CassandraTemplate implements CassandraOperations, ApplicationEventPublisherAware {
private final CassandraConverter converter;
private final CqlOperations cqlOperations;
private final MappingContext, CassandraPersistentProperty> mappingContext;
private final SpelAwareProxyProjectionFactory projectionFactory;
private final StatementFactory statementFactory;
private @Nullable ApplicationEventPublisher eventPublisher;
/**
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link Session} and a default
* {@link MappingCassandraConverter}.
*
* @param session {@link Session} used to interact with Cassandra; must not be {@literal null}.
* @see CassandraConverter
* @see Session
*/
public CassandraTemplate(Session session) {
this(session, newConverter());
}
/**
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link Session} and
* {@link CassandraConverter}.
*
* @param session {@link Session} used to interact with Cassandra; must not be {@literal null}.
* @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be
* {@literal null}.
* @see CassandraConverter
* @see Session
*/
public CassandraTemplate(Session session, CassandraConverter converter) {
this(new DefaultSessionFactory(session), converter);
}
/**
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link SessionFactory} and
* {@link CassandraConverter}.
*
* @param sessionFactory {@link SessionFactory} used to interact with Cassandra; must not be {@literal null}.
* @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be
* {@literal null}.
* @see CassandraConverter
* @see SessionFactory
*/
public CassandraTemplate(SessionFactory sessionFactory, CassandraConverter converter) {
this(new CqlTemplate(sessionFactory), converter);
}
/**
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link CqlOperations} and
* {@link CassandraConverter}.
*
* @param cqlOperations {@link CqlOperations} used to interact with Cassandra; must not be {@literal null}.
* @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be
* {@literal null}.
* @see CassandraConverter
* @see Session
*/
public CassandraTemplate(CqlOperations cqlOperations, CassandraConverter converter) {
Assert.notNull(cqlOperations, "CqlOperations must not be null");
Assert.notNull(converter, "CassandraConverter must not be null");
this.converter = converter;
this.cqlOperations = cqlOperations;
this.mappingContext = converter.getMappingContext();
this.projectionFactory = new SpelAwareProxyProjectionFactory();
this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#batchOps()
*/
@Override
public CassandraBatchOperations batchOps() {
return new CassandraBatchTemplate(this);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#getConverter()
*/
@Override
public CassandraConverter getConverter() {
return this.converter;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#CqlOperations()
*/
@Override
public CqlOperations getCqlOperations() {
return this.cqlOperations;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#getTableName(java.lang.Class)
*/
@Override
public CqlIdentifier getTableName(Class entityClass) {
return getRequiredPersistentEntity(entityClass).getTableName();
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
// -------------------------------------------------------------------------
// Methods dealing with static CQL
// -------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#select(java.lang.String, java.lang.Class)
*/
@Override
public List select(String cql, Class entityClass) {
Assert.hasText(cql, "Statement must not be empty");
return select(new SimpleStatement(cql), entityClass);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#stream(java.lang.String, java.lang.Class)
*/
@Override
public Stream stream(String cql, Class entityClass) throws DataAccessException {
Assert.hasText(cql, "Statement must not be empty");
Assert.notNull(entityClass, "Entity type must not be null");
return stream(new SimpleStatement(cql), entityClass);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(java.lang.String, java.lang.Class)
*/
@Override
public T selectOne(String cql, Class entityClass) {
Assert.hasText(cql, "Statement must not be empty");
Assert.notNull(entityClass, "Entity type must not be null");
return selectOne(new SimpleStatement(cql), entityClass);
}
// -------------------------------------------------------------------------
// Methods dealing with com.datastax.driver.core.Statement
// -------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#select(com.datastax.driver.core.Statement, java.lang.Class)
*/
@Override
public List select(Statement statement, Class entityClass) {
Assert.notNull(statement, "Statement must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
Function mapper = getMapper(entityClass, entityClass, QueryUtils.getTableName(statement));
return getCqlOperations().query(statement, (row, rowNum) -> mapper.apply(row));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#slice(com.datastax.driver.core.Statement, java.lang.Class)
*/
@Override
public Slice slice(Statement statement, Class entityClass) {
Assert.notNull(statement, "Statement must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
ResultSet resultSet = getCqlOperations().queryForResultSet(statement);
Function mapper = getMapper(entityClass, entityClass, QueryUtils.getTableName(statement));
return QueryUtils.readSlice(resultSet, (row, rowNum) -> mapper.apply(row), 0, getEffectiveFetchSize(statement));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#stream(com.datastax.driver.core.Statement, java.lang.Class)
*/
@Override
public Stream stream(Statement statement, Class entityClass) throws DataAccessException {
Assert.notNull(statement, "Statement must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
ResultSet resultSet = getCqlOperations().queryForResultSet(statement);
return StreamSupport.stream(resultSet.spliterator(), false)
.map(getMapper(entityClass, entityClass, QueryUtils.getTableName(statement)));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(com.datastax.driver.core.Statement, java.lang.Class)
*/
@Override
public T selectOne(Statement statement, Class entityClass) {
return select(statement, entityClass).stream().findFirst().orElse(null);
}
// -------------------------------------------------------------------------
// Methods dealing with org.springframework.data.cassandra.core.query.Query
// -------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#select(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public List select(Query query, Class entityClass) throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return doSelect(query, entityClass, getTableName(entityClass), entityClass);
}
List doSelect(Query query, Class entityClass, CqlIdentifier tableName, Class returnType) {
Function mapper = getMapper(entityClass, returnType, tableName);
RegularStatement select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass), tableName);
return getCqlOperations().query(select, (row, rowNum) -> mapper.apply(row));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#slice(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public Slice slice(Query query, Class entityClass) throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
RegularStatement select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass));
return slice(select, entityClass);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#stream(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public Stream stream(Query query, Class entityClass) throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return doStream(query, entityClass, getTableName(entityClass), entityClass);
}
Stream doStream(Query query, Class entityClass, CqlIdentifier tableName, Class returnType) {
RegularStatement statement = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass),
tableName);
ResultSet resultSet = getCqlOperations().queryForResultSet(statement);
return StreamSupport.stream(resultSet.spliterator(), false).map(getMapper(entityClass, returnType, tableName));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public T selectOne(Query query, Class entityClass) throws DataAccessException {
List result = select(query, entityClass);
return result.isEmpty() ? null : result.get(0);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#update(org.springframework.data.cassandra.core.query.Query, org.springframework.data.cassandra.core.query.Update, java.lang.Class)
*/
@Override
public boolean update(Query query, org.springframework.data.cassandra.core.query.Update update, Class entityClass)
throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(update, "Update must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
Statement updateStatement = getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass));
return getCqlOperations().execute(updateStatement);
}
@Nullable
WriteResult doUpdate(Query query, org.springframework.data.cassandra.core.query.Update update, Class entityClass,
CqlIdentifier tableName) {
RegularStatement updateStatement = getStatementFactory().update(query, update,
getRequiredPersistentEntity(entityClass), tableName);
return getCqlOperations().execute(new StatementCallback(updateStatement));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#delete(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public boolean delete(Query query, Class entityClass) throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
WriteResult result = doDelete(query, entityClass, getTableName(entityClass));
return result != null && result.wasApplied();
}
@Nullable
WriteResult doDelete(Query query, Class entityClass, CqlIdentifier tableName) {
RegularStatement delete = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass), tableName);
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
WriteResult writeResult = getCqlOperations().execute(new StatementCallback(delete));
maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName));
return writeResult;
}
// -------------------------------------------------------------------------
// Methods dealing with entities
// -------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#count(java.lang.Class)
*/
@Override
public long count(Class entityClass) {
Assert.notNull(entityClass, "Entity type must not be null");
Select select = QueryBuilder.select().countAll().from(getTableName(entityClass).toCql());
Long count = getCqlOperations().queryForObject(select, Long.class);
return count != null ? count : 0L;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#count(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public long count(Query query, Class entityClass) throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return doCount(query, entityClass, getTableName(entityClass));
}
long doCount(Query query, Class entityClass, CqlIdentifier tableName) {
RegularStatement countStatement = getStatementFactory().count(query, getRequiredPersistentEntity(entityClass),
tableName);
Long count = getCqlOperations().queryForObject(countStatement, Long.class);
return count != null ? count : 0L;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#exists(java.lang.Object, java.lang.Class)
*/
@Override
public boolean exists(Object id, Class entityClass) {
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass);
Select select = QueryBuilder.select().from(getTableName(entityClass).toCql());
getConverter().write(id, select.where(), entity);
return getCqlOperations().queryForResultSet(select).iterator().hasNext();
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#exists(org.springframework.data.cassandra.core.query.Query, java.lang.Class)
*/
@Override
public boolean exists(Query query, Class entityClass) throws DataAccessException {
Assert.notNull(query, "Query must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
return doExists(query, entityClass, getTableName(entityClass));
}
boolean doExists(Query query, Class entityClass, CqlIdentifier tableName) {
RegularStatement select = getStatementFactory().select(query.limit(1), getRequiredPersistentEntity(entityClass),
tableName);
return getCqlOperations().queryForResultSet(select).iterator().hasNext();
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOneById(java.lang.Object, java.lang.Class)
*/
@Override
public T selectOneById(Object id, Class entityClass) {
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
CqlIdentifier tableName = getTableName(entityClass);
Select select = QueryBuilder.select().all().from(tableName.toCql());
getConverter().write(id, select.where(), getRequiredPersistentEntity(entityClass));
Function mapper = getMapper(entityClass, entityClass, tableName);
List result = getCqlOperations().query(select, (row, rowNum) -> mapper.apply(row));
return result.isEmpty() ? null : result.get(0);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object)
*/
@Override
public T insert(T entity) {
return insert(entity, InsertOptions.empty()).getEntity();
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
*/
@Override
public EntityWriteResult insert(T entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "InsertOptions must not be null");
return doInsert(entity, options, getTableName(entity));
}
EntityWriteResult doInsert(T entity, WriteOptions options, CqlIdentifier tableName) {
CassandraPersistentEntity persistentEntity = getRequiredPersistentEntity(entity.getClass());
Insert insert = QueryUtils.createInsertQuery(tableName.toCql(), entity, options, getConverter(), persistentEntity);
maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, insert));
// noinspection ConstantConditions
WriteResult result = getCqlOperations().execute(new StatementCallback(insert));
maybeEmitEvent(new AfterSaveEvent<>(entity, tableName));
return EntityWriteResult.of(result, entity);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object)
*/
@Override
public T update(T entity) {
return update(entity, UpdateOptions.empty()).getEntity();
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
*/
@Override
public EntityWriteResult update(T entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "UpdateOptions must not be null");
CqlIdentifier tableName = getTableName(entity);
Update update = QueryUtils.createUpdateQuery(tableName.toCql(), entity, options, getConverter());
maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, update));
// noinspection ConstantConditions
WriteResult result = getCqlOperations().execute(new StatementCallback(update));
maybeEmitEvent(new AfterSaveEvent<>(entity, tableName));
return EntityWriteResult.of(result, entity);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#delete(java.lang.Object)
*/
@Override
public void delete(Object entity) {
delete(entity, QueryOptions.empty());
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#delete(java.lang.Object, org.springframework.data.cassandra.core.cql.QueryOptions)
*/
@Override
public WriteResult delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Assert.notNull(options, "QueryOptions must not be null");
CqlIdentifier tableName = getTableName(entity);
Delete delete = QueryUtils.createDeleteQuery(tableName.toCql(), entity, options, getConverter());
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entity.getClass(), tableName));
// noinspection ConstantConditions
WriteResult result = getCqlOperations().execute(new StatementCallback(delete));
maybeEmitEvent(new AfterDeleteEvent<>(delete, entity.getClass(), tableName));
return result;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#deleteById(java.lang.Object, java.lang.Class)
*/
@Override
public boolean deleteById(Object id, Class entityClass) {
Assert.notNull(id, "Id must not be null");
Assert.notNull(entityClass, "Entity type must not be null");
CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass);
CqlIdentifier tableName = entity.getTableName();
Delete delete = QueryBuilder.delete().from(tableName.toCql());
getConverter().write(id, delete.where(), entity);
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
boolean result = getCqlOperations().execute(delete);
maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName));
return result;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.CassandraOperations#truncate(java.lang.Class)
*/
@Override
public void truncate(Class entityClass) {
Assert.notNull(entityClass, "Entity type must not be null");
CqlIdentifier tableName = getTableName(entityClass);
Truncate truncate = QueryBuilder.truncate(tableName.toCql());
maybeEmitEvent(new BeforeDeleteEvent<>(truncate, entityClass, tableName));
getCqlOperations().execute(truncate);
maybeEmitEvent(new AfterDeleteEvent<>(truncate, entityClass, tableName));
}
// -------------------------------------------------------------------------
// Fluent API entry points
// -------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ExecutableSelectOperation#query(java.lang.Class)
*/
@Override
public ExecutableSelect query(Class domainType) {
return new ExecutableSelectOperationSupport(this).query(domainType);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ExecutableInsertOperation#insert(java.lang.Class)
*/
@Override
public ExecutableInsert insert(Class domainType) {
return new ExecutableInsertOperationSupport(this).insert(domainType);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ExecutableUpdateOperation#update(java.lang.Class)
*/
@Override
public ExecutableUpdate update(Class domainType) {
return new ExecutableUpdateOperationSupport(this).update(domainType);
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.ExecutableDeleteOperation#remove(java.lang.Class)
*/
@Override
public ExecutableDelete delete(Class domainType) {
return new ExecutableDeleteOperationSupport(this).delete(domainType);
}
// -------------------------------------------------------------------------
// Implementation hooks and helper methods
// -------------------------------------------------------------------------
/**
* Returns the {@link CassandraMappingContext} used by this template to access mapping meta-data in order to store
* (map) object to Cassandra tables.
*
* @return the {@link CassandraMappingContext} used by this template.
* @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext
*/
protected MappingContext, CassandraPersistentProperty> getMappingContext() {
return this.mappingContext;
}
/**
* Returns a reference to the configured {@link ProjectionFactory} used by this template to process CQL query
* projections.
*
* @return a reference to the configured {@link ProjectionFactory} used by this template to process CQL query
* projections.
* @see org.springframework.data.projection.SpelAwareProxyProjectionFactory
* @since 2.1
*/
protected SpelAwareProxyProjectionFactory getProjectionFactory() {
return this.projectionFactory;
}
/**
* Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
*
* @return the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
* @see org.springframework.data.cassandra.core.StatementFactory
* @since 2.1
*/
protected StatementFactory getStatementFactory() {
return this.statementFactory;
}
private CqlIdentifier getTableName(Object entity) {
return getRequiredPersistentEntity(entity.getClass()).getTableName();
}
private CassandraPersistentEntity getRequiredPersistentEntity(Class entityType) {
return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entityType));
}
private int getConfiguredFetchSize(Session session) {
return session.getCluster().getConfiguration().getQueryOptions().getFetchSize();
}
@SuppressWarnings("ConstantConditions")
private int getEffectiveFetchSize(Statement statement) {
if (statement.getFetchSize() > 0) {
return statement.getFetchSize();
}
if (getCqlOperations() instanceof CassandraAccessor) {
CassandraAccessor accessor = (CassandraAccessor) getCqlOperations();
if (accessor.getFetchSize() != -1) {
return accessor.getFetchSize();
}
}
return getCqlOperations().execute(this::getConfiguredFetchSize);
}
@SuppressWarnings("unchecked")
private Function getMapper(Class entityType, Class targetType, CqlIdentifier tableName) {
Class typeToRead = resolveTypeToRead(entityType, targetType);
return row -> {
maybeEmitEvent(new AfterLoadEvent(row, targetType, tableName));
Object source = getConverter().read(typeToRead, row);
T result = (T) (targetType.isInterface() ? getProjectionFactory().createProjection(targetType, source) : source);
if (result != null) {
maybeEmitEvent(new AfterConvertEvent<>(row, result, tableName));
}
return result;
};
}
private Class resolveTypeToRead(Class entityType, Class targetType) {
return targetType.isInterface() || targetType.isAssignableFrom(entityType) ? entityType : targetType;
}
private void maybeEmitEvent(ApplicationEvent event) {
if (eventPublisher != null) {
eventPublisher.publishEvent(event);
}
}
private static MappingCassandraConverter newConverter() {
MappingCassandraConverter converter = new MappingCassandraConverter();
converter.afterPropertiesSet();
return converter;
}
@Value
static class StatementCallback implements SessionCallback, CqlProvider {
@lombok.NonNull Statement statement;
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.SessionCallback#doInSession(org.springframework.data.cassandra.Session)
*/
@Override
public WriteResult doInSession(Session session) throws DriverException, DataAccessException {
return WriteResult.of(session.execute(statement));
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.CqlProvider#getCql()
*/
@Override
public String getCql() {
return statement.toString();
}
}
}