Skip to main content

sqlx_pool_registry/
provider.rs

1use crate::sqlx::PgPool;
2
3/// Trait for providing database pools with read/write routing.
4///
5/// Implementations can provide separate read and write pools for load distribution,
6/// or use a single pool for both operations.
7///
8/// # Thread Safety
9///
10/// Implementations must be `Clone`, `Send`, and `Sync` to work with async Rust
11/// and be shared across tasks.
12///
13/// # When to Use Each Method
14///
15/// ## `.read()` - For Read Operations
16///
17/// Use for queries that:
18/// - Don't modify data (SELECT without FOR UPDATE)
19/// - Can tolerate slight staleness (eventual consistency)
20/// - Benefit from load distribution
21///
22/// Examples: user listings, analytics, dashboards, search
23///
24/// ## `.write()` - For Write Operations
25///
26/// Use for operations that:
27/// - Modify data (INSERT, UPDATE, DELETE)
28/// - Require transactions
29/// - Need locking reads (SELECT FOR UPDATE)
30/// - Require read-after-write consistency
31///
32/// Examples: creating records, updates, deletes, transactions
33///
34/// # Example Implementation
35///
36/// ```
37/// use sqlx_pool_registry::sqlx::{self, PgPool};
38/// use sqlx_pool_registry::PoolProvider;
39///
40/// #[derive(Clone)]
41/// struct MyPools {
42///     primary: PgPool,
43///     replica: Option<PgPool>,
44/// }
45///
46/// impl PoolProvider for MyPools {
47///     fn read(&self) -> &PgPool {
48///         self.replica.as_ref().unwrap_or(&self.primary)
49///     }
50///
51///     fn write(&self) -> &PgPool {
52///         &self.primary
53///     }
54/// }
55/// ```
56pub trait PoolProvider: Clone + Send + Sync + 'static {
57    /// Get a pool for read operations.
58    ///
59    /// May return a read replica for load distribution, or fall back to
60    /// the primary pool if no replica is configured.
61    fn read(&self) -> &PgPool;
62
63    /// Get a pool for write operations.
64    ///
65    /// Should return the primary pool for operations that require writes,
66    /// locking reads, or read-after-write consistency.
67    fn write(&self) -> &PgPool;
68}
69
70/// Implement PoolProvider for PgPool for backward compatibility.
71///
72/// This allows existing code using `PgPool` directly to work with generic
73/// code that accepts `impl PoolProvider` without any changes.
74///
75/// # Example
76///
77/// ```rust,no_run
78/// use sqlx_pool_registry::sqlx::{self, PgPool};
79/// use sqlx_pool_registry::PoolProvider;
80///
81/// async fn query_user<P: PoolProvider>(pools: &P, id: i64) -> Result<String, sqlx::Error> {
82///     sqlx::query_scalar("SELECT name FROM users WHERE id = $1")
83///         .bind(id)
84///         .fetch_one(pools.read())
85///         .await
86/// }
87///
88/// # async fn example() -> Result<(), sqlx::Error> {
89/// let pool = PgPool::connect("postgresql://localhost/db").await?;
90///
91/// // Works with PgPool directly
92/// let name = query_user(&pool, 1).await?;
93/// # Ok(())
94/// # }
95/// ```
96impl PoolProvider for PgPool {
97    fn read(&self) -> &PgPool {
98        self
99    }
100
101    fn write(&self) -> &PgPool {
102        self
103    }
104}