1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
//! `Connection` is the main structure to interact with the database.
use async_trait::async_trait;
use anyhow::Result;
use super::{QueryResult, Statement};
/// Trait describing capabilities of a database connection:
/// - executing statements, batches, transactions
#[async_trait(?Send)]
pub trait Connection {
/// Executes a single SQL statement
///
/// # Arguments
/// * `stmt` - the SQL statement
async fn execute(&self, stmt: impl Into<Statement>) -> Result<QueryResult> {
let mut results = self.batch(std::iter::once(stmt)).await?;
Ok(results.remove(0))
}
/// Executes a batch of SQL statements.
/// Each statement is going to run in its own transaction,
/// unless they're wrapped in BEGIN and END
///
/// # Arguments
/// * `stmts` - SQL statements
/// ```
async fn batch(
&self,
stmts: impl IntoIterator<Item = impl Into<Statement>>,
) -> Result<Vec<QueryResult>>;
/// Executes an SQL transaction.
/// Does not support nested transactions - do not use BEGIN or END
/// inside a transaction.
///
/// # Arguments
/// * `stmts` - SQL statements
/// ```
async fn transaction(
&self,
stmts: impl IntoIterator<Item = impl Into<Statement>>,
) -> Result<Vec<QueryResult>> {
// TODO: Vec is not a good fit for popping the first element,
// let's return a templated collection instead and let the user
// decide where to store the result.
let mut ret: Vec<QueryResult> = self
.batch(
std::iter::once(Statement::new("BEGIN"))
.chain(stmts.into_iter().map(|s| s.into()))
.chain(std::iter::once(Statement::new("END"))),
)
.await?
.into_iter()
.skip(1)
.collect();
ret.pop();
Ok(ret)
}
}