1
//! A tenant connection that keeps its pool alive.
2

            
3
use crate::user::userpool::registry::TenantPool;
4
use sqlx::pool::PoolConnection;
5
use sqlx::{PgConnection, Postgres};
6
use std::ops::{Deref, DerefMut};
7
use std::sync::Arc;
8

            
9
/// A checked-out connection, holding the tenant pool it came from.
10
///
11
/// The anchor is what makes the residency bound true. A permit lives inside
12
/// [`TenantPool`] and is returned when the last handle drops, so handing back a
13
/// bare `PoolConnection` released the permit while the connection was still
14
/// open — sqlx keeps the pool alive behind the connection, so the process could
15
/// then admit a ninth resident pool and exceed the budget it claims to enforce.
16
///
17
/// Dereferences to [`PgConnection`], so `&mut *conn` and `&mut conn` reach an
18
/// executor exactly as they did before.
19
pub struct TenantConnection {
20
    conn: PoolConnection<Postgres>,
21
    /// `None` for the global/admin pool, which is bounded by its own cap rather
22
    /// than by residency permits.
23
    _anchor: Option<Arc<TenantPool>>,
24
}
25

            
26
impl TenantConnection {
27
    /// Only the tenant-routing half builds these, and that half is excluded
28
    /// from server's own `cfg(test)` runs.
29
    #[cfg(not(test))]
30
234
    pub(crate) const fn tenant(conn: PoolConnection<Postgres>, anchor: Arc<TenantPool>) -> Self {
31
234
        Self {
32
234
            conn,
33
234
            _anchor: Some(anchor),
34
234
        }
35
234
    }
36

            
37
    /// Only the test and `test-utils` arms of `User::get_connection` route a
38
    /// global connection through the tenant type; production always has a pool.
39
    #[cfg(any(test, feature = "test-utils"))]
40
23931
    pub(crate) const fn global(conn: PoolConnection<Postgres>) -> Self {
41
23931
        Self {
42
23931
            conn,
43
23931
            _anchor: None,
44
23931
        }
45
23931
    }
46
}
47

            
48
impl Deref for TenantConnection {
49
    type Target = PgConnection;
50

            
51
    fn deref(&self) -> &Self::Target {
52
        &self.conn
53
    }
54
}
55

            
56
impl DerefMut for TenantConnection {
57
35360
    fn deref_mut(&mut self) -> &mut Self::Target {
58
35360
        &mut self.conn
59
35360
    }
60
}