Skip to main content

core_crypto_keystore/
transactionlike.rs

1use std::ops::Deref;
2
3use rusqlite::Connection;
4
5use crate::{CryptoKeystoreResult, transaction::TransactionConnection};
6
7/// A guard unifying the types of connection provided by [`Transactionlike`].
8#[derive(derive_more::From)]
9pub(crate) enum ConnectionGuard<'a> {
10    Rusqlite(&'a rusqlite::Transaction<'a>),
11    Keystore(TransactionConnection),
12}
13
14impl<'a> Deref for ConnectionGuard<'a> {
15    type Target = Connection;
16
17    fn deref(&self) -> &Self::Target {
18        match self {
19            ConnectionGuard::Rusqlite(transaction) => (*transaction).deref(),
20            ConnectionGuard::Keystore(transaction_connection) => transaction_connection.deref(),
21        }
22    }
23}
24
25/// A transaction which might come from our own keystore implementation, or directly from rusqlite.
26///
27/// We want type-level assurance that all database mutation occurs within the scope of a transaction,
28/// but it doesn't really matter if the transaction type is our own or provided by rusqlite.
29/// There are use cases for both:
30///
31/// - within a migration, it's simpler to use a rusqlite transaction
32/// - for general usage, our transaction implementation works better in a long-lived async context
33///
34/// This type generalizes over borrowed instances of each.
35#[derive(derive_more::From)]
36pub enum Transactionlike<'a> {
37    Rusqlite(&'a rusqlite::Transaction<'a>),
38    Keystore(&'a crate::Transaction),
39}
40
41impl<'a> Transactionlike<'a> {
42    pub(crate) fn conn(&self) -> CryptoKeystoreResult<ConnectionGuard<'a>> {
43        let guard = match self {
44            Transactionlike::Rusqlite(transaction) => (*transaction).into(),
45            Transactionlike::Keystore(transaction) => transaction.conn()?.into(),
46        };
47        Ok(guard)
48    }
49}