203 lines
5.1 KiB
Markdown
203 lines
5.1 KiB
Markdown
# 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<DB>,
|
|
},
|
|
/// Lazy acquisition from pool
|
|
Owned {
|
|
pool: Pool,
|
|
conn: Option<PoolConnection<DB>>,
|
|
},
|
|
}
|
|
```
|
|
|
|
## 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<DB>
|
|
```
|
|
|
|
- **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<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
|
|
```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<MySql>` |
|
|
| `postgres` | `PgPool` | `PoolConnection<Postgres>` |
|
|
| `sqlite` | `SqlitePool` | `PoolConnection<Sqlite>` |
|
|
|
|
## 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<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)
|
|
```
|