taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

db.rs (2771B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::{
     18     path::Path,
     19     str::FromStr as _,
     20     sync::{
     21         OnceLock,
     22         atomic::{AtomicUsize, Ordering},
     23     },
     24 };
     25 
     26 use sqlx::{
     27     PgPool,
     28     postgres::{PgConnectOptions, PgPoolOptions},
     29 };
     30 use taler_api::config::DbCfg;
     31 use taler_common::{
     32     config::{Config, parser::ConfigSource},
     33     db::{dbinit, pool},
     34 };
     35 
     36 use crate::setup_tracing;
     37 
     38 pub async fn db_test_setup(src: ConfigSource) -> PgPool {
     39     let cfg = Config::from_file(src, None::<&str>).unwrap();
     40     let name = format!("{}db-postgres", src.component_name);
     41     let sect = cfg.section(&name);
     42     let db_cfg = DbCfg::parse(sect).unwrap();
     43     db_test_setup_manual(db_cfg.sql_dir.as_ref(), src.component_name).await
     44 }
     45 
     46 pub async fn db_test_setup_manual(sql_dir: &Path, component_name: &str) -> PgPool {
     47     setup_tracing();
     48     let cfg = test_db().await;
     49     let pool = pool(cfg, &component_name.replace("-", "_")).await.unwrap();
     50     let mut conn = pool.acquire().await.unwrap();
     51 
     52     dbinit(&mut conn, sql_dir, component_name, true)
     53         .await
     54         .unwrap();
     55     pool
     56 }
     57 
     58 static MASTER_POOL: OnceLock<PgPool> = OnceLock::new();
     59 
     60 const DB: &str = "postgres:///taler_rust_check";
     61 static NB_DB: AtomicUsize = AtomicUsize::new(0);
     62 
     63 async fn test_db() -> PgConnectOptions {
     64     let master = MASTER_POOL.get_or_init(|| {
     65         PgPoolOptions::new()
     66             .max_connections(20)
     67             .test_before_acquire(false)
     68             .after_release(|_conn, _| Box::pin(async move { Ok(false) }))
     69             .connect_lazy(DB)
     70             .expect("pg pool")
     71     });
     72     let idx = NB_DB.fetch_add(1, Ordering::Relaxed);
     73     // Cleanup test db
     74     let name = format!("taler_rust_test_{idx}");
     75     let mut conn = master.acquire().await.unwrap();
     76     sqlx::raw_sql(&format!("DROP DATABASE IF EXISTS {name}"))
     77         .execute(&mut *conn)
     78         .await
     79         .unwrap();
     80     sqlx::raw_sql(&format!("CREATE DATABASE {name}"))
     81         .execute(&mut *conn)
     82         .await
     83         .unwrap();
     84     drop(conn);
     85     PgConnectOptions::from_str(&format!("postgresql:/{name}")).unwrap()
     86 }