use std::fmt::Debug;
use std::sync::Arc;
use async_trait::async_trait;
use cdk_common::database::{self, DbTransactionFinalizer, Error, MintDatabase};
use crate::common::migrate;
use crate::database::{ConnectionWithTransaction, DatabaseExecutor};
use crate::pool::{DatabasePool, Pool, PooledResource};
mod auth;
mod completed_operations;
mod keys;
mod keyvalue;
mod proofs;
mod quotes;
mod saga;
mod signatures;
#[rustfmt::skip]
mod migrations {
include!(concat!(env!("OUT_DIR"), "/migrations_mint.rs"));
}
pub use auth::SQLMintAuthDatabase;
#[cfg(feature = "prometheus")]
use cdk_prometheus::METRICS;
use migrations::MIGRATIONS;
#[derive(Debug, Clone)]
pub struct SQLMintDatabase<RM>
where
RM: DatabasePool + 'static,
{
pub(crate) pool: Arc<Pool<RM>>,
}
#[allow(missing_debug_implementations)]
pub struct SQLTransaction<RM>
where
RM: DatabasePool + 'static,
{
pub(crate) inner: ConnectionWithTransaction<RM::Connection, PooledResource<RM>>,
}
impl<RM> SQLMintDatabase<RM>
where
RM: DatabasePool + 'static,
{
pub async fn new<X>(db: X) -> Result<Self, Error>
where
X: Into<RM::Config>,
{
let pool = Pool::new(db.into());
Self::migrate(pool.get().map_err(|e| Error::Database(Box::new(e)))?).await?;
Ok(Self { pool })
}
async fn migrate(conn: PooledResource<RM>) -> Result<(), Error> {
let tx = ConnectionWithTransaction::new(conn).await?;
migrate(&tx, RM::Connection::name(), MIGRATIONS).await?;
tx.commit().await?;
Ok(())
}
}
#[async_trait]
impl<RM> database::MintTransaction<Error> for SQLTransaction<RM> where RM: DatabasePool + 'static {}
#[async_trait]
impl<RM> DbTransactionFinalizer for SQLTransaction<RM>
where
RM: DatabasePool + 'static,
{
type Err = Error;
async fn commit(self: Box<Self>) -> Result<(), Error> {
let result = self.inner.commit().await;
#[cfg(feature = "prometheus")]
{
let success = result.is_ok();
METRICS.record_mint_operation("transaction_commit", success);
METRICS.record_mint_operation_histogram("transaction_commit", success, 1.0);
}
Ok(result?)
}
async fn rollback(self: Box<Self>) -> Result<(), Error> {
let result = self.inner.rollback().await;
#[cfg(feature = "prometheus")]
{
let success = result.is_ok();
METRICS.record_mint_operation("transaction_rollback", success);
METRICS.record_mint_operation_histogram("transaction_rollback", success, 1.0);
}
Ok(result?)
}
}
#[async_trait]
impl<RM> MintDatabase<Error> for SQLMintDatabase<RM>
where
RM: DatabasePool + 'static,
{
async fn begin_transaction(
&self,
) -> Result<Box<dyn database::MintTransaction<Error> + Send + Sync>, Error> {
let tx = SQLTransaction {
inner: ConnectionWithTransaction::new(
self.pool.get().map_err(|e| Error::Database(Box::new(e)))?,
)
.await?,
};
Ok(Box::new(tx))
}
}