5.1 KiB
5.1 KiB
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
pub enum ConnProvider<'a> {
/// Reference to existing connection
Borrowed {
conn: &'a mut PoolConnection<DB>,
},
/// Lazy acquisition from pool
Owned {
pool: Pool,
conn: Option<PoolConnection<DB>>,
},
}
Constructors
from_ref
Use an existing connection:
let mut conn = pool.acquire().await?;
let mut provider = ConnProvider::from_ref(&mut conn);
from_pool
Lazy acquisition from pool:
let mut provider = ConnProvider::from_pool(pool.clone());
// Connection acquired on first get_conn() call
Getting the Connection
let conn = provider.get_conn().await?;
// Returns &mut PoolConnection<DB>
- Borrowed: Returns reference immediately
- Owned: Acquires on first call, returns same connection on subsequent calls
Use Cases
Reuse Existing Connection
async fn process_batch(conn: &mut PoolConnection<MySql>) -> 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
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
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
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<MySql> |
postgres |
PgPool |
PoolConnection<Postgres> |
sqlite |
SqlitePool |
PoolConnection<Sqlite> |
Example: Service Layer
use sqlx_record::prelude::*;
struct UserService;
impl UserService {
async fn create_with_profile(
provider: &mut ConnProvider<'_>,
name: &str,
bio: &str,
) -> Result<Uuid, Error> {
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)