Add migration to calculate the account statistics for the past

This commit is contained in:
2019-09-29 23:40:21 +02:00
parent 43a298267e
commit de00be477d
3 changed files with 117 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
package database.common;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class V22_0_1__calculateAccountStatistics extends BaseJavaMigration {
private static class TransactionPeriodAccountsContainer {
public Long transactionAmount;
public Long expensePeriodId;
public Long fromAccountId;
public Long toAccountId;
public TransactionPeriodAccountsContainer(Long transactionAmount, Long expensePeriodId, Long fromAccountId, Long toAccountId) {
this.transactionAmount = transactionAmount;
this.expensePeriodId = expensePeriodId;
this.fromAccountId = fromAccountId;
this.toAccountId = toAccountId;
}
}
private static final String GET_CONTAINERS_SQL = "SELECT t.amount, p.id, t.from_account_id, t.to_account_id FROM \"transaction\" t INNER JOIN link_transaction_period ltp ON ltp.transaction_id = t.id INNER JOIN period p ON p.id = ltp.period_id WHERE p.type = 'EXPENSE'";
private static final String ACCOUNT_STATISTIC_EXISTS_SQL = "SELECT id FROM account_statistic WHERE account_id = ? AND period_id = ?";
private static final String ACCOUNT_STATISTIC_UPDATE_FROM_SQL = "UPDATE account_statistic SET spending_total_from = spending_total_from + ?, transaction_count_from = transaction_count_from + 1 WHERE id = ?";
private static final String ACCOUNT_STATISTIC_UPDATE_TO_SQL = "UPDATE account_statistic SET spending_total_to = spending_total_to + ?, transaction_count_to = transaction_count_to + 1 WHERE id = ?";
private static final String ACCOUNT_STATISTIC_INSERT_FROM_SQL = "INSERT INTO account_statistic(account_id, period_id, spending_total_from, transaction_count_from, spending_total_to, transaction_count_to) VALUES(?, ?, ?, 1, 0, 0)";
private static final String ACCOUNT_STATISTIC_INSERT_TO_SQL = "INSERT INTO account_statistic(account_id, period_id, spending_total_from, transaction_count_from, spending_total_to, transaction_count_to) VALUES(?, ?, 0, 0, ?, 1)";
@Override
public void migrate(Context context) throws Exception {
final List<TransactionPeriodAccountsContainer> cons = getContainers(context);
for (TransactionPeriodAccountsContainer con : cons) {
handleAccount(con, context, true);
handleAccount(con, context, false);
}
}
private void handleAccount(TransactionPeriodAccountsContainer con, Context context, boolean from) throws SQLException {
try (PreparedStatement statement =
context
.getConnection()
.prepareStatement(ACCOUNT_STATISTIC_EXISTS_SQL)) {
statement.setLong(1, from ? con.fromAccountId : con.toAccountId);
statement.setLong(2, con.expensePeriodId);
final ResultSet rs = statement.executeQuery();
boolean found = false;
// Only one possible entry because of the unique constraint
while(rs.next()) {
found = true;
try (PreparedStatement statementUpdate =
context
.getConnection()
.prepareStatement(from ? ACCOUNT_STATISTIC_UPDATE_FROM_SQL : ACCOUNT_STATISTIC_UPDATE_TO_SQL)) {
statementUpdate.setLong(1, con.transactionAmount);
statementUpdate.setLong(2, rs.getLong(1));
statementUpdate.executeUpdate();
}
}
// We need to create a new account_statistic entry for the tuple {account_id;report_id}
if (!found) {
try (PreparedStatement statementInsert =
context
.getConnection()
.prepareStatement(from ? ACCOUNT_STATISTIC_INSERT_FROM_SQL : ACCOUNT_STATISTIC_INSERT_TO_SQL)) {
statementInsert.setLong(1, from ? con.fromAccountId : con.toAccountId);
statementInsert.setLong(2, con.expensePeriodId);
statementInsert.setLong(3, con.transactionAmount);
statementInsert.execute();
}
}
}
}
private List<TransactionPeriodAccountsContainer> getContainers(Context context) throws SQLException {
try (PreparedStatement statement =
context
.getConnection()
.prepareStatement(GET_CONTAINERS_SQL)) {
final ResultSet rs = statement.executeQuery();
final List<TransactionPeriodAccountsContainer> cons = new ArrayList<>();
while(rs.next()) {
cons.add(new TransactionPeriodAccountsContainer(
rs.getLong(1), // transaction amount
rs.getLong(2), // expense period ID
rs.getLong(3), // from account ID
rs.getLong(4) // to account ID
));
}
return cons;
}
}
}

View File

@@ -0,0 +1,4 @@
/**
* Package for Java based database migrations via Flyway
*/
package database;

View File

@@ -0,0 +1,2 @@
ALTER TABLE account_statistic
ADD CONSTRAINT un_account_statistic_account_period UNIQUE (account_id,period_id);