org.fluentjdbc.DatabaseBulkUpdateBuilder Maven / Gradle / Ivy
package org.fluentjdbc;
import org.fluentjdbc.util.ExceptionUtil;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.fluentjdbc.DatabaseStatement.addBatch;
/**
* Fluently generate a UPDATE ...
statement for a list of objects. Create with a list of object
* and use {@link #setField(String, Function)} to pass in a function that will be called for each object
* in the list to create the SET field = ?
value and {@link #where(String, Function)}
* which will be called for each object to create the WHERE field = ?
value.
*
* Example:
*
*
* public void updateAll(List<TagType> tagTypes, Connection connection) {
* tagTypesTable.bulkUpdate(tagTypes)
* .where("id", TagType::getId)
* .setField("name", TagType::getName)
* .execute(connection);
* }
*
*/
@ParametersAreNonnullByDefault
public class DatabaseBulkUpdateBuilder implements
DatabaseBulkQueryable>,
DatabaseBulkUpdatable>
{
private final DatabaseTable table;
private final Iterable objects;
private final List whereConditions = new ArrayList<>();
private final List> whereParameters = new ArrayList<>();
private final List updateFields = new ArrayList<>();
private final List> updateParameters = new ArrayList<>();
public DatabaseBulkUpdateBuilder(DatabaseTable table, Iterable objects) {
this.table = table;
this.objects = objects;
}
/**
* Adds a function that will be called for each object to get the value for
* {@link PreparedStatement#setObject(int, Object)} for each row in the bulk update
* to extract the values for the WHERE fieldName = ?
clause
*/
@Override
public DatabaseBulkUpdateBuilder where(String field, Function value) {
whereConditions.add(field + " = ?");
whereParameters.add(value);
return this;
}
/**
* Adds a function that will be called for each object to get the value for
* {@link PreparedStatement#setObject(int, Object)} for each row in the bulk update
* to extract the values for the SET fieldName = ?
clause
*/
@Override
public DatabaseBulkUpdateBuilder setField(String fieldName, Function transformer) {
updateFields.add(fieldName);
updateParameters.add(transformer);
return this;
}
/**
* Executes UPDATE table SET field = ?, ... WHERE field = ? AND ...
* and calls {@link PreparedStatement#addBatch()} for each row
*
* @return the sum count of all the rows updated
*/
public int execute(Connection connection) {
try (PreparedStatement statement = connection.prepareStatement(createUpdateStatement())) {
List> parameters = new ArrayList<>();
parameters.addAll(updateParameters);
parameters.addAll(whereParameters);
addBatch(statement, objects, parameters);
int[] counts = statement.executeBatch();
return IntStream.of(counts).sum();
} catch (SQLException e) {
throw ExceptionUtil.softenCheckedException(e);
}
}
@Nonnull
@CheckReturnValue
private String createUpdateStatement() {
return "update " + table.getTableName()
+ " set " + updateFields.stream().map(column -> column + " = ?").collect(Collectors.joining(","))
+ (whereConditions.isEmpty() ? "" : " where " + String.join(" and ", whereConditions));
}
}