com.scalar.db.sql.springdata.ScalarDbJdbcAggregateTemplate Maven / Gradle / Ivy
package com.scalar.db.sql.springdata;
import com.scalar.db.sql.util.SqlUtils;
import java.sql.ResultSet;
import java.util.Collections;
import javax.annotation.Nonnull;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* An extended ${@link JdbcAggregateTemplate} customized for ScalarDB SQL. This prevents users from
* using some APIs that are not supported in ScalarDB by throwing ${@link
* UnsupportedOperationException}.
*/
public class ScalarDbJdbcAggregateTemplate extends JdbcAggregateTemplate {
private final NamedParameterJdbcOperations operations;
public ScalarDbJdbcAggregateTemplate(
ApplicationContext publisher,
RelationalMappingContext context,
JdbcConverter converter,
DataAccessStrategy dataAccessStrategy,
NamedParameterJdbcOperations operations) {
super(publisher, context, converter, dataAccessStrategy);
this.operations = operations;
}
public ScalarDbJdbcAggregateTemplate(
ApplicationEventPublisher publisher,
RelationalMappingContext context,
JdbcConverter converter,
DataAccessStrategy dataAccessStrategy,
NamedParameterJdbcOperations operations) {
super(publisher, context, converter, dataAccessStrategy);
this.operations = operations;
}
@Override
@Nonnull
public T save(@Nonnull T instance) {
throw new UnsupportedOperationException(
"This operation isn't supported in ScalarDB SQL: save. "
+ "The original method depends on underlying database's autoincrement ID column, "
+ "but ScalarDB SQL doesn't support the feature. Please use insert() or update() of ScalarDbRepository");
}
@Override
public long count(@Nonnull Class> domainType) {
// ScalarDB SQL doesn't have COUNT() function.
int count = 0;
for (Object unused : findAll(domainType)) {
count++;
}
return count;
}
// Spring Data JDBC issues `SELECT ... FROM ... ORDER BY ...` (without WHERE) that isn't supported
// by ScalarDB SQL.
@Override
@Nonnull
public Iterable findAll(@Nonnull Class domainType, @Nonnull Sort sort) {
throw new UnsupportedOperationException(
"This operation isn't supported in ScalarDB SQL: findAll(Sort)");
}
// Spring Data JDBC implicitly issues `SELECT COUNT(*) FROM ...` that isn't supported by ScalarDB
// SQL.
@Override
@Nonnull
public Page findAll(@Nonnull Class domainType, @Nonnull Pageable pageable) {
throw new UnsupportedOperationException(
"This operation isn't supported in ScalarDB SQL: findAll(Pageable)");
}
// Spring Data JDBC issues `DELETE FROM ...` (without WHERE) that isn't supported by ScalarDB SQL.
@Override
public void deleteAll(@Nonnull Class> domainType) {
throw new UnsupportedOperationException(
"This operation isn't supported in ScalarDB SQL: deleteAll");
}
public String begin() {
return operations.execute(
"BEGIN",
ps -> {
if (!ps.execute()) {
throw new IllegalStateException(
"This return value isn't ResultSet unexpectedly: BEGIN");
}
ResultSet resultSet = ps.getResultSet();
if (!resultSet.next()) {
throw new IllegalStateException(
"This return value is an empty ResultSet unexpectedly: BEGIN");
}
return resultSet.getString(1);
});
}
public void prepare() {
operations.update("PREPARE", Collections.emptyMap());
}
public void validate() {
operations.update("VALIDATE", Collections.emptyMap());
}
public void suspend() {
operations.update("SUSPEND", Collections.emptyMap());
}
public void commit() {
operations.update("COMMIT", Collections.emptyMap());
}
public void rollback() {
operations.update("ROLLBACK", Collections.emptyMap());
}
private void executeWithTransactionId(String clause, String transactionId) {
String escapedTxId;
escapedTxId = SqlUtils.escapeString(transactionId);
operations.update(String.format("%s '%s'", clause, escapedTxId), Collections.emptyMap());
}
public void join(String transactionId) {
executeWithTransactionId("JOIN", transactionId);
}
public void resume(String transactionId) {
executeWithTransactionId("RESUME", transactionId);
}
}