mod.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. //! SQL database implementation of the Mint
  2. //!
  3. //! This is a generic SQL implementation for the mint storage layer. Any database can be plugged in
  4. //! as long as standard ANSI SQL is used, as Postgres and SQLite would understand it.
  5. //!
  6. //! This implementation also has a rudimentary but standard migration and versioning system.
  7. //!
  8. //! The trait expects an asynchronous interaction, but it also provides tools to spawn blocking
  9. //! clients in a pool and expose them to an asynchronous environment, making them compatible with
  10. //! Mint.
  11. use std::fmt::Debug;
  12. use std::sync::Arc;
  13. use async_trait::async_trait;
  14. use cdk_common::database::{self, DbTransactionFinalizer, Error, MintDatabase};
  15. use crate::common::migrate;
  16. use crate::database::{ConnectionWithTransaction, DatabaseExecutor};
  17. use crate::pool::{DatabasePool, Pool, PooledResource};
  18. #[cfg(feature = "auth")]
  19. mod auth;
  20. mod completed_operations;
  21. mod keys;
  22. mod keyvalue;
  23. mod proofs;
  24. mod quotes;
  25. mod saga;
  26. mod signatures;
  27. #[rustfmt::skip]
  28. mod migrations {
  29. include!(concat!(env!("OUT_DIR"), "/migrations_mint.rs"));
  30. }
  31. #[cfg(feature = "auth")]
  32. pub use auth::SQLMintAuthDatabase;
  33. #[cfg(feature = "prometheus")]
  34. use cdk_prometheus::METRICS;
  35. use migrations::MIGRATIONS;
  36. /// Mint SQL Database
  37. #[derive(Debug, Clone)]
  38. pub struct SQLMintDatabase<RM>
  39. where
  40. RM: DatabasePool + 'static,
  41. {
  42. pub(crate) pool: Arc<Pool<RM>>,
  43. }
  44. /// SQL Transaction Writer
  45. #[allow(missing_debug_implementations)]
  46. pub struct SQLTransaction<RM>
  47. where
  48. RM: DatabasePool + 'static,
  49. {
  50. pub(crate) inner: ConnectionWithTransaction<RM::Connection, PooledResource<RM>>,
  51. }
  52. impl<RM> SQLMintDatabase<RM>
  53. where
  54. RM: DatabasePool + 'static,
  55. {
  56. /// Creates a new instance
  57. pub async fn new<X>(db: X) -> Result<Self, Error>
  58. where
  59. X: Into<RM::Config>,
  60. {
  61. let pool = Pool::new(db.into());
  62. Self::migrate(pool.get().map_err(|e| Error::Database(Box::new(e)))?).await?;
  63. Ok(Self { pool })
  64. }
  65. /// Migrate
  66. async fn migrate(conn: PooledResource<RM>) -> Result<(), Error> {
  67. let tx = ConnectionWithTransaction::new(conn).await?;
  68. migrate(&tx, RM::Connection::name(), MIGRATIONS).await?;
  69. tx.commit().await?;
  70. Ok(())
  71. }
  72. }
  73. #[async_trait]
  74. impl<RM> database::MintTransaction<Error> for SQLTransaction<RM> where RM: DatabasePool + 'static {}
  75. #[async_trait]
  76. impl<RM> DbTransactionFinalizer for SQLTransaction<RM>
  77. where
  78. RM: DatabasePool + 'static,
  79. {
  80. type Err = Error;
  81. async fn commit(self: Box<Self>) -> Result<(), Error> {
  82. let result = self.inner.commit().await;
  83. #[cfg(feature = "prometheus")]
  84. {
  85. let success = result.is_ok();
  86. METRICS.record_mint_operation("transaction_commit", success);
  87. METRICS.record_mint_operation_histogram("transaction_commit", success, 1.0);
  88. }
  89. Ok(result?)
  90. }
  91. async fn rollback(self: Box<Self>) -> Result<(), Error> {
  92. let result = self.inner.rollback().await;
  93. #[cfg(feature = "prometheus")]
  94. {
  95. let success = result.is_ok();
  96. METRICS.record_mint_operation("transaction_rollback", success);
  97. METRICS.record_mint_operation_histogram("transaction_rollback", success, 1.0);
  98. }
  99. Ok(result?)
  100. }
  101. }
  102. #[async_trait]
  103. impl<RM> MintDatabase<Error> for SQLMintDatabase<RM>
  104. where
  105. RM: DatabasePool + 'static,
  106. {
  107. async fn begin_transaction(
  108. &self,
  109. ) -> Result<Box<dyn database::MintTransaction<Error> + Send + Sync>, Error> {
  110. let tx = SQLTransaction {
  111. inner: ConnectionWithTransaction::new(
  112. self.pool.get().map_err(|e| Error::Database(Box::new(e)))?,
  113. )
  114. .await?,
  115. };
  116. Ok(Box::new(tx))
  117. }
  118. }