summaryrefslogtreecommitdiff
path: root/src/domain/unit_of_work.rs
blob: 7d6a0e34de2a7a4dd0b60b2e6698036ec217b0c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use anyhow::Result;
use std::sync::Arc;

/// Unit of Work pattern for managing transactional boundaries
pub trait UnitOfWork: Send + Sync {
    /// Begin a new transaction
    fn begin(&self) -> Result<Box<dyn Transaction>>;
}

/// Transaction interface for atomic operations
pub trait Transaction: Send + Sync {
    /// Commit all changes in this transaction
    fn commit(self: Box<Self>) -> Result<()>;

    /// Rollback all changes in this transaction
    fn rollback(self: Box<Self>) -> Result<()>;

    /// Get repositories within this transaction context
    fn client_repository(&self) -> Arc<dyn crate::domain::DomainClientRepository>;
    fn auth_code_repository(&self) -> Arc<dyn crate::domain::DomainAuthCodeRepository>;
    fn token_repository(&self) -> Arc<dyn crate::domain::DomainTokenRepository>;
    fn audit_repository(&self) -> Arc<dyn crate::domain::DomainAuditRepository>;
}

/// OAuth2-specific transactional operations
pub struct OAuthUnitOfWork {
    uow: Arc<dyn UnitOfWork>,
}

impl OAuthUnitOfWork {
    pub fn new(uow: Arc<dyn UnitOfWork>) -> Self {
        Self { uow }
    }

    /// Execute OAuth2 authorization code exchange atomically
    pub fn exchange_authorization_code<F>(&self, operation: F) -> Result<()>
    where
        F: FnOnce(&dyn Transaction) -> Result<()>,
    {
        let tx = self.uow.begin()?;
        match operation(tx.as_ref()) {
            Ok(_) => tx.commit(),
            Err(e) => {
                let _ = tx.rollback(); // Log but don't override original error
                Err(e)
            }
        }
    }

    /// Execute token refresh atomically
    pub fn refresh_tokens<F>(&self, operation: F) -> Result<()>
    where
        F: FnOnce(&dyn Transaction) -> Result<()>,
    {
        let tx = self.uow.begin()?;
        match operation(tx.as_ref()) {
            Ok(_) => tx.commit(),
            Err(e) => {
                let _ = tx.rollback();
                Err(e)
            }
        }
    }
}