diff --git a/sqlx-core/src/connection.rs b/sqlx-core/src/connection.rs index f92ea114d..34125189c 100644 --- a/sqlx-core/src/connection.rs +++ b/sqlx-core/src/connection.rs @@ -1,3 +1,5 @@ +//! Contains the `Connection` and `Connect` traits. + use std::convert::TryInto; use futures_core::future::BoxFuture; @@ -9,16 +11,31 @@ use crate::url::Url; /// Represents a single database connection rather than a pool of database connections. /// -/// Prefer running queries from [Pool] unless there is a specific need for a single, continuous +/// Connections can be manually established outside of a [`Pool`] with [`Connect::connect`]. +/// +/// Prefer running queries from [`Pool`] unless there is a specific need for a single, sticky /// connection. pub trait Connection where Self: Send + 'static, Self: Executor, { - /// Starts a transaction. + /// Starts a new transaction. /// - /// Returns [`Transaction`](struct.Transaction.html). + /// Wraps this connection in [`Transaction`] to manage the transaction lifecycle. To get the + /// original connection back, explicitly [`commit`] or [`rollback`] and this connection will + /// be returned. + /// + /// ```rust,ignore + /// let mut tx = conn.begin().await?; + /// // conn is now inaccessible as its wrapped in a transaction + /// + /// let conn = tx.commit().await?; + /// // conn is back now and out of the transaction + /// ``` + /// + /// [`commit`]: crate::transaction::Transaction::commit + /// [`rollback`]: crate::transaction::Transaction::rollback fn begin(self) -> BoxFuture<'static, crate::Result>> where Self: Sized, @@ -26,10 +43,14 @@ where Box::pin(Transaction::new(0, self)) } - /// Close this database connection. + /// Explicitly close this database connection. + /// + /// This method is **not required** for safe and consistent operation. However, it is + /// recommended to call it instead of letting a connection `drop` as the database server + /// will be faster at cleaning up resources. fn close(self) -> BoxFuture<'static, crate::Result>; - /// Verifies a connection to the database is still alive. + /// Checks if a connection to the database is still valid. fn ping(&mut self) -> BoxFuture>; } diff --git a/sqlx-core/src/pool/connection.rs b/sqlx-core/src/pool/connection.rs index 156a25471..a78fd783f 100644 --- a/sqlx-core/src/pool/connection.rs +++ b/sqlx-core/src/pool/connection.rs @@ -78,7 +78,6 @@ impl Connection for PoolConnection where C: Connect, { - /// Detach the connection from the pool and close it nicely. fn close(mut self) -> BoxFuture<'static, crate::Result> { Box::pin(async move { let live = self.live.take().expect("PoolConnection double-dropped"); diff --git a/sqlx-core/src/transaction.rs b/sqlx-core/src/transaction.rs index 9d6fcd2e5..366cae1a7 100644 --- a/sqlx-core/src/transaction.rs +++ b/sqlx-core/src/transaction.rs @@ -9,22 +9,43 @@ use crate::describe::Describe; use crate::executor::{Execute, Executor, RefExecutor}; use crate::runtime::spawn; -/// Represents a database transaction. +/// Represents an in-progress database transaction. +/// +/// A transaction ends with a call to [`commit`] or [`rollback`] in which the wrapped connection ( +/// or outer transaction) is returned. If neither are called before the transaction +/// goes out-of-scope, [`rollback`] is called. In other words, [`rollback`] is called on `drop` +/// if the transaction is still in-progress. +/// +/// ```rust,ignore +/// // Acquire a new connection and immediately begin a transaction +/// let mut tx = pool.begin().await?; +/// +/// sqlx::query("INSERT INTO articles (slug) VALUES ('this-is-a-slug')") +/// .execute(&mut tx) +/// // As we didn't fill in all the required fields in this INSERT, +/// // this statement will fail. Since we used `?`, this function +/// // will immediately return with the error which will cause +/// // this transaction to be rolled back. +/// .await?; +/// ``` +/// +/// [`commit`]: #method.commit +/// [`rollback`]: #method.rollback // Transaction> // Transaction -pub struct Transaction +pub struct Transaction where - T: Connection, + C: Connection, { - inner: Option, + inner: Option, depth: u32, } -impl Transaction +impl Transaction where - T: Connection, + C: Connection, { - pub(crate) async fn new(depth: u32, mut inner: T) -> crate::Result { + pub(crate) async fn new(depth: u32, mut inner: C) -> crate::Result { if depth == 0 { inner.execute("BEGIN").await?; } else { @@ -41,13 +62,13 @@ where /// Creates a new save point in the current transaction and returns /// a new `Transaction` object to manage its scope. - pub async fn begin(self) -> crate::Result>> { + pub async fn begin(self) -> crate::Result>> { Transaction::new(self.depth, self).await } /// Commits the current transaction or save point. /// Returns the inner connection or transaction. - pub async fn commit(mut self) -> crate::Result { + pub async fn commit(mut self) -> crate::Result { let mut inner = self.inner.take().expect(ERR_FINALIZED); let depth = self.depth; @@ -64,7 +85,7 @@ where /// Rollback the current transaction or save point. /// Returns the inner connection or transaction. - pub async fn rollback(mut self) -> crate::Result { + pub async fn rollback(mut self) -> crate::Result { let mut inner = self.inner.take().expect(ERR_FINALIZED); let depth = self.depth; @@ -82,32 +103,32 @@ where const ERR_FINALIZED: &str = "(bug) transaction already finalized"; -impl Deref for Transaction +impl Deref for Transaction where - T: Connection, + C: Connection, { - type Target = T; + type Target = C; fn deref(&self) -> &Self::Target { self.inner.as_ref().expect(ERR_FINALIZED) } } -impl DerefMut for Transaction +impl DerefMut for Transaction where - T: Connection, + C: Connection, { fn deref_mut(&mut self) -> &mut Self::Target { self.inner.as_mut().expect(ERR_FINALIZED) } } -impl Connection for Transaction +impl Connection for Transaction where - T: Connection, + C: Connection, { // Close is equivalent to - fn close(mut self) -> BoxFuture<'static, crate::Result> { + fn close(mut self) -> BoxFuture<'static, crate::Result> { Box::pin(async move { let mut inner = self.inner.take().expect(ERR_FINALIZED); @@ -131,22 +152,22 @@ where } #[inline] - fn ping(&mut self) -> BoxFuture<'_, crate::Result> { + fn ping(&mut self) -> BoxFuture<'_, crate::Result> { self.deref_mut().ping() } } -impl Executor for Transaction +impl Executor for Transaction where DB: Database, - T: Connection, + C: Connection, { - type Database = T::Database; + type Database = C::Database; fn execute<'e, 'q: 'e, 'c: 'e, E: 'e>( &'c mut self, query: E, - ) -> BoxFuture<'e, crate::Result> + ) -> BoxFuture<'e, crate::Result> where E: Execute<'q, Self::Database>, { @@ -164,7 +185,7 @@ where fn describe<'e, 'q, E: 'e>( &'e mut self, query: E, - ) -> BoxFuture<'e, crate::Result>> + ) -> BoxFuture<'e, crate::Result>> where E: Execute<'q, Self::Database>, { @@ -172,10 +193,10 @@ where } } -impl<'e, DB, T> RefExecutor<'e> for &'e mut Transaction +impl<'e, DB, C> RefExecutor<'e> for &'e mut Transaction where DB: Database, - T: Connection, + C: Connection, { type Database = DB; @@ -187,9 +208,9 @@ where } } -impl Drop for Transaction +impl Drop for Transaction where - T: Connection, + C: Connection, { fn drop(&mut self) { if self.depth > 0 {