libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

GcDAO.kt (3192B)


      1 /*
      2  * This file is part of LibEuFin.
      3  * Copyright (C) 2024, 2025, 2026 Taler Systems S.A.
      4 
      5  * LibEuFin is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU Affero General Public License as
      7  * published by the Free Software Foundation; either version 3, or
      8  * (at your option) any later version.
      9 
     10  * LibEuFin is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
     13  * Public License for more details.
     14 
     15  * You should have received a copy of the GNU Affero General Public
     16  * License along with LibEuFin; see the file COPYING.  If not, see
     17  * <http://www.gnu.org/licenses/>
     18  */
     19 
     20 package tech.libeufin.bank.db
     21 
     22 import tech.libeufin.common.db.withStatement
     23 import tech.libeufin.common.micros
     24 import java.time.Duration
     25 import java.time.Instant
     26 
     27 /** Data access logic for garbage collection */
     28 class GcDAO(private val db: Database) {
     29     /** Run garbage collection  */
     30     suspend fun collect(
     31         timestamp: Instant,
     32         abortAfter: Duration,
     33         cleanAfter: Duration,
     34         deleteAfter: Duration
     35     ) = db.conn { conn ->
     36         val abortAfterMicro = timestamp.minus(abortAfter).micros()
     37         val cleanAfterMicro = timestamp.minus(cleanAfter).micros()
     38         val deleteAfterMicro = timestamp.minus(deleteAfter).micros()
     39         
     40         // Abort pending operations
     41         conn.withStatement(
     42             """
     43                 UPDATE taler_withdrawal_operations SET aborted = true WHERE creation_date < ? AND NOT EXISTS(
     44                     SELECT FROM prepared_transfers JOIN taler_withdrawal_operations USING (withdrawal_id)
     45                 )
     46             """
     47         ) {
     48             bind(abortAfterMicro) 
     49             executeUpdate()
     50         }
     51 
     52         // Clean aborted operations, expired challenges and expired tokens
     53         for (smt in listOf(
     54             """DELETE FROM taler_withdrawal_operations WHERE aborted = true AND creation_date < ? AND NOT EXISTS(
     55                 SELECT FROM prepared_transfers JOIN taler_withdrawal_operations USING (withdrawal_id)
     56             )""",
     57             "DELETE FROM tan_challenges WHERE expiration_date < ?",
     58             "DELETE FROM bearer_tokens WHERE expiration_time < ?"
     59         )) {
     60             conn.withStatement(smt) {
     61                 bind(cleanAfterMicro) 
     62                 executeUpdate()
     63             }
     64         }
     65 
     66         // Delete old bank transactions, linked operations are deleted by CASCADE
     67         conn.withStatement(
     68             "DELETE FROM bank_account_transactions WHERE transaction_date < ?"
     69         ) {
     70             bind(deleteAfterMicro) 
     71             executeUpdate()
     72         }
     73 
     74         // Hard delete soft deleted customer without bank transactions, bank account are deleted by CASCADE
     75         conn.withStatement("""
     76             DELETE FROM customers WHERE deleted_at IS NOT NULL AND NOT EXISTS(
     77                 SELECT FROM bank_account_transactions NATURAL JOIN bank_accounts
     78                     WHERE owning_customer_id=customer_id
     79             )
     80         """) {
     81             executeUpdate()
     82         }
     83 
     84         // TODO clean stats
     85     }
     86 }