Add migration to calculate the account statistics for the past
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
financer-server/src/main/java/database/package-info.java
Normal file
4
financer-server/src/main/java/database/package-info.java
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Package for Java based database migrations via Flyway
|
||||
*/
|
||||
package database;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE account_statistic
|
||||
ADD CONSTRAINT un_account_statistic_account_period UNIQUE (account_id,period_id);
|
||||
Reference in New Issue
Block a user