# sqlx-record ConnProvider Skill Guide to flexible connection management. ## Triggers - "connection provider", "conn provider" - "borrow connection", "pool connection" - "lazy connection", "connection management" ## Overview `ConnProvider` enables flexible connection handling: - **Borrowed**: Use an existing connection reference - **Owned**: Lazily acquire from pool on first use ## Enum Variants ```rust pub enum ConnProvider<'a> { /// Reference to existing connection Borrowed { conn: &'a mut PoolConnection, }, /// Lazy acquisition from pool Owned { pool: Pool, conn: Option>, }, } ``` ## Constructors ### from_ref Use an existing connection: ```rust let mut conn = pool.acquire().await?; let mut provider = ConnProvider::from_ref(&mut conn); ``` ### from_pool Lazy acquisition from pool: ```rust let mut provider = ConnProvider::from_pool(pool.clone()); // Connection acquired on first get_conn() call ``` ## Getting the Connection ```rust let conn = provider.get_conn().await?; // Returns &mut PoolConnection ``` - **Borrowed**: Returns reference immediately - **Owned**: Acquires on first call, returns same connection on subsequent calls ## Use Cases ### Reuse Existing Connection ```rust async fn process_batch(conn: &mut PoolConnection) -> Result<()> { let mut provider = ConnProvider::from_ref(conn); do_work_a(&mut provider).await?; do_work_b(&mut provider).await?; // Same connection do_work_c(&mut provider).await?; // Same connection Ok(()) } ``` ### Lazy Pool Connection ```rust async fn maybe_needs_db(pool: MySqlPool, condition: bool) -> Result<()> { let mut provider = ConnProvider::from_pool(pool); if condition { // Connection acquired here (first use) let conn = provider.get_conn().await?; sqlx::query("SELECT 1").execute(&mut **conn).await?; } // If condition is false, no connection was ever acquired Ok(()) } ``` ### Uniform Interface ```rust async fn do_database_work(provider: &mut ConnProvider<'_>) -> Result<()> { let conn = provider.get_conn().await?; // Works regardless of Borrowed or Owned sqlx::query("INSERT INTO logs (msg) VALUES (?)") .bind("operation completed") .execute(&mut **conn) .await?; Ok(()) } // Call with borrowed let mut conn = pool.acquire().await?; do_database_work(&mut ConnProvider::from_ref(&mut conn)).await?; // Call with pool do_database_work(&mut ConnProvider::from_pool(pool)).await?; ``` ### Transaction-like Patterns ```rust async fn multi_step_operation(pool: MySqlPool) -> Result<()> { let mut provider = ConnProvider::from_pool(pool); // All operations use same connection step_1(&mut provider).await?; step_2(&mut provider).await?; step_3(&mut provider).await?; // Connection returned to pool when provider drops Ok(()) } ``` ## Database-Specific Types The concrete types depend on the enabled feature: | Feature | Pool Type | Connection Type | |---------|-----------|-----------------| | `mysql` | `MySqlPool` | `PoolConnection` | | `postgres` | `PgPool` | `PoolConnection` | | `sqlite` | `SqlitePool` | `PoolConnection` | ## Example: Service Layer ```rust use sqlx_record::prelude::*; struct UserService; impl UserService { async fn create_with_profile( provider: &mut ConnProvider<'_>, name: &str, bio: &str, ) -> Result { let conn = provider.get_conn().await?; // Create user let user_id = new_uuid(); sqlx::query("INSERT INTO users (id, name) VALUES (?, ?)") .bind(user_id) .bind(name) .execute(&mut **conn) .await?; // Create profile (same connection) sqlx::query("INSERT INTO profiles (user_id, bio) VALUES (?, ?)") .bind(user_id) .bind(bio) .execute(&mut **conn) .await?; Ok(user_id) } } // Usage let mut provider = ConnProvider::from_pool(pool); let user_id = UserService::create_with_profile(&mut provider, "Alice", "Hello!").await?; ``` ## Connection Lifecycle ``` from_pool(pool) from_ref(&mut conn) │ │ ▼ ▼ Owned { Borrowed { pool, conn: &mut PoolConnection conn: None } } │ │ │ │ get_conn() │ get_conn() ▼ ▼ pool.acquire() return conn │ │ ▼ │ Owned { │ pool, │ conn: Some(acquired) │ } │ │ │ │ get_conn() (subsequent) │ ▼ │ return &mut acquired │ │ │ ▼ ▼ Drop: conn returned Drop: nothing (borrowed) ```