libeufin

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

GcDAO.kt (3082B)


      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 WHERE prepared_transfers.withdrawal_id=taler_withdrawal_operations.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 < ?",
     55             "DELETE FROM tan_challenges WHERE expiration_date < ?",
     56             "DELETE FROM bearer_tokens WHERE expiration_time < ?"
     57         )) {
     58             conn.withStatement(smt) {
     59                 bind(cleanAfterMicro) 
     60                 executeUpdate()
     61             }
     62         }
     63 
     64         // Delete old bank transactions, linked operations are deleted by CASCADE
     65         conn.withStatement(
     66             "DELETE FROM bank_account_transactions WHERE transaction_date < ?"
     67         ) {
     68             bind(deleteAfterMicro) 
     69             executeUpdate()
     70         }
     71 
     72         // Hard delete soft deleted customer without bank transactions, bank account are deleted by CASCADE
     73         conn.withStatement("""
     74             DELETE FROM customers WHERE deleted_at IS NOT NULL AND NOT EXISTS(
     75                 SELECT FROM bank_account_transactions NATURAL JOIN bank_accounts
     76                     WHERE owning_customer_id=customer_id
     77             )
     78         """) {
     79             executeUpdate()
     80         }
     81 
     82         // TODO clean stats
     83     }
     84 }