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 + '}'; } }