package org.simpleflatmapper.datastax;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.PreparedStatement;
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 java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class DatastaxCrud<T, K> {
/**
* can keep ref to prepared statement accross time
* https://datastax.github.io/java-driver/features/statements/prepared/
*/
private final PreparedStatement readQuery;
private final PreparedStatement deleteQuery;
private final PreparedStatement deleteQueryWithTimestamp;
private final PreparedStatement insertQuery;
private final PreparedStatement insertQueryWithTtlAndTimestamp;
private final PreparedStatement insertQueryWithTtl;
private final PreparedStatement insertQueryWithTimestamp;
private final BoundStatementMapper<K> keySetter;
private final BoundStatementMapper<K> keySetterWith1Option;
private final BoundStatementMapper<T> insertSetter;
private final DatastaxMapper<T> selectMapper;
private final int numberOfColumns;
private final Session session;
public DatastaxCrud(
PreparedStatement insertQuery,
PreparedStatement insertQueryWithTtlAndTimestamp,
PreparedStatement insertQueryWithTtl,
PreparedStatement insertQueryWithTimestamp,
PreparedStatement readQuery,
PreparedStatement deleteQuery,
PreparedStatement deleteQueryWithTimestamp,
BoundStatementMapper<T> insertSetter,
BoundStatementMapper<K> keySetter,
BoundStatementMapper<K> keySetterWith1Option,
DatastaxMapper<T> selectMapper, int numberOfColumns,
Session session) {
this.readQuery = readQuery;
this.deleteQuery = deleteQuery;
this.insertQuery = insertQuery;
this.insertQueryWithTtlAndTimestamp = insertQueryWithTtlAndTimestamp;
this.insertQueryWithTtl = insertQueryWithTtl;
this.insertQueryWithTimestamp = insertQueryWithTimestamp;
this.deleteQueryWithTimestamp = deleteQueryWithTimestamp;
this.keySetter = keySetter;
this.insertSetter = insertSetter;
this.keySetterWith1Option = keySetterWith1Option;
this.selectMapper = selectMapper;
this.numberOfColumns = numberOfColumns;
this.session = session;
}
public void save(T value) {
saveAsync(value).getUninterruptibly();
}
public void save(T value, int ttl, long timestamp) {
saveAsync(value, ttl, timestamp).getUninterruptibly();
}
public void saveWithTtl(T value, int ttl) {
saveWithTtlAsync(value, ttl).getUninterruptibly();
}
public void saveWithTimestamp(T value, long timestamp) {
saveWithTimestampAsync(value, timestamp).getUninterruptibly();
}
public UninterruptibleFuture<Void> saveAsync(T value) {
BoundStatement boundStatement = saveQuery(value);
return new NoResultFuture(session.executeAsync(boundStatement));
}
public UninterruptibleFuture<Void> saveAsync(T value, int ttl, long timestamp) {
BoundStatement boundStatement = saveQuery(value, ttl, timestamp);
return new NoResultFuture(session.executeAsync(boundStatement));
}
public UninterruptibleFuture<Void> saveWithTtlAsync(T value, int ttl) {
BoundStatement boundStatement = saveQueryWithTtl(value, ttl);
return new NoResultFuture(session.executeAsync(boundStatement));
}
public UninterruptibleFuture<Void> saveWithTimestampAsync(T value, long timestamp) {
BoundStatement boundStatement = saveQueryWithTimestamp(value, timestamp);
return new NoResultFuture(session.executeAsync(boundStatement));
}
public BoundStatement saveQuery(T value) {
return insertSetter.mapTo(value, insertQuery.bind());
}
public BoundStatement saveQuery(T value, int ttl, long timestamp) {
BoundStatement boundStatement = insertQueryWithTtlAndTimestamp.bind();
insertSetter.mapTo(value, boundStatement);
boundStatement.setInt(numberOfColumns, ttl);
boundStatement.setLong(numberOfColumns + 1, timestamp);
return boundStatement;
}
public BoundStatement saveQueryWithTtl(T value, int ttl) {
BoundStatement boundStatement = insertQueryWithTtl.bind();
insertSetter.mapTo(value, boundStatement);
boundStatement.setInt(numberOfColumns, ttl);
return boundStatement;
}
public BoundStatement saveQueryWithTimestamp(T value, long timestamp) {
BoundStatement boundStatement = insertQueryWithTimestamp.bind();
insertSetter.mapTo(value, boundStatement);
boundStatement.setLong(numberOfColumns, timestamp);
return boundStatement;
}
public T read(K key) {
return readAsync(key).getUninterruptibly();
}
public UninterruptibleFuture<T> readAsync(K key) {
BoundStatement boundStatement = keySetter.mapTo(key, readQuery.bind());
return new OneResultFuture<T>(session.executeAsync(boundStatement), selectMapper);
}
public void delete(K key) {
deleteAsync(key).getUninterruptibly();
}
public void delete(K key, long timestamp) {
deleteAsync(key, timestamp).getUninterruptibly();
}
public UninterruptibleFuture<Void> deleteAsync(K key, long timestamp) {
BoundStatement boundStatement = deleteQuery(key, timestamp);
ResultSetFuture resultSetFuture = session.executeAsync(boundStatement);
return new NoResultFuture(resultSetFuture);
}
public UninterruptibleFuture<Void> deleteAsync(K key) {
BoundStatement boundStatement = deleteQuery(key);
ResultSetFuture resultSetFuture = session.executeAsync(boundStatement);
return new NoResultFuture(resultSetFuture);
}
public BoundStatement deleteQuery(K key) {
return keySetter.mapTo(key, deleteQuery.bind());
}
public BoundStatement deleteQuery(K key, long timestamp) {
BoundStatement boundStatement = deleteQueryWithTimestamp.bind();
boundStatement.setLong(0, timestamp);
return keySetterWith1Option.mapTo(key, boundStatement);
}
private class OneResultFuture<T> implements UninterruptibleFuture<T> {
private final ResultSetFuture resultSetFuture;
private final DatastaxMapper<T> mapper;
public OneResultFuture(ResultSetFuture resultSetFuture, DatastaxMapper<T> mapper) {
this.resultSetFuture = resultSetFuture;
this.mapper = mapper;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return resultSetFuture.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return resultSetFuture.isCancelled();
}
@Override
public boolean isDone() {
return resultSetFuture.isDone();
}
@Override
public T get() throws InterruptedException, ExecutionException {
ResultSet rs = resultSetFuture.get();
return mapOneSelect(rs);
}
@Override
public T getUninterruptibly() {
ResultSet rs = resultSetFuture.getUninterruptibly();
return mapOneSelect(rs);
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
ResultSet rs = resultSetFuture.get(timeout, unit);
return mapOneSelect(rs);
}
private T mapOneSelect(ResultSet rs) {
Row row = rs.one();
if (row != null) {
return mapper.map(row);
}
return null;
}
@Override
public void addListener(Runnable listener, Executor executor) {
resultSetFuture.addListener(listener, executor);
}
}
private class NoResultFuture implements UninterruptibleFuture<Void> {
private final ResultSetFuture resultSetFuture;
public NoResultFuture(ResultSetFuture resultSetFuture) {
this.resultSetFuture = resultSetFuture;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return resultSetFuture.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return resultSetFuture.isCancelled();
}
@Override
public boolean isDone() {
return resultSetFuture.isDone();
}
@Override
public Void get() throws InterruptedException, ExecutionException {
resultSetFuture.get();
return null;
}
@Override
public Void getUninterruptibly() {
resultSetFuture.getUninterruptibly();
return null;
}
@Override
public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
resultSetFuture.get(timeout, unit);
return null;
}
@Override
public void addListener(Runnable listener, Executor executor) {
resultSetFuture.addListener(listener, executor);
}
}
@Override
public String toString() {
return "DatastaxCrud{\n" +
"\n\treadQuery=" + readQuery +
",\n\tdeleteQuery=" + deleteQuery +
",\n\tdeleteQueryWithTimestamp=" + deleteQueryWithTimestamp +
",\n\tinsertQuery=" + insertQuery +
",\n\tinsertQueryWithTtlAndTimestamp=" + insertQueryWithTtlAndTimestamp +
",\n\tinsertQueryWithTtl=" + insertQueryWithTtl +
",\n\tinsertQueryWithTimestamp=" + insertQueryWithTimestamp +
",\n\tkeySetter=" + keySetter +
",\n\tkeySetterWith1Option=" + keySetterWith1Option +
",\n\tinsertSetter=" + insertSetter +
",\n\tselectMapper=" + selectMapper +
",\n\tnumberOfColumns=" + numberOfColumns +
",\n\tsession=" + session +
'}';
}
}