From 26b1f420a715a9b8b37cea616d9c5ea39ffa51c0 Mon Sep 17 00:00:00 2001 From: stoically Date: Wed, 16 Feb 2022 07:21:51 +0100 Subject: [PATCH] docs: Acquire examples and alternative --- .github/workflows/sqlx.yml | 7 ++++ Cargo.lock | 1 + sqlx-core/Cargo.toml | 3 ++ sqlx-core/src/acquire.rs | 61 +++++++++++++++++++++++++++++ sqlx-core/src/sqlite/options/mod.rs | 1 - 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 44964b509b..c2fe6f9e88 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -71,6 +71,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: + postgres: [14, 9_6] runtime: [async-std, tokio, actix] tls: [native-tls, rustls] steps: @@ -90,12 +91,18 @@ jobs: target key: ${{ runner.os }}-test-${{ hashFiles('**/Cargo.lock') }} + - run: | + docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }} postgres_${{ matrix.postgres }} + docker exec postgres_${{ matrix.postgres }} bash -c "until pg_isready; do sleep 1; done" + - uses: actions-rs/cargo@v1 with: command: test args: > --manifest-path sqlx-core/Cargo.toml --features offline,all-databases,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx cli: name: CLI Binaries diff --git a/Cargo.lock b/Cargo.lock index 2f0ddab8d8..528ef46865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2455,6 +2455,7 @@ dependencies = [ "sha2", "smallvec", "sqlformat", + "sqlx", "sqlx-rt", "stringprep", "thiserror", diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index e8912206fa..5126503ef8 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -164,3 +164,6 @@ bstr = { version = "0.2.17", default-features = false, features = ["std"], optio git2 = { version = "0.13.25", default-features = false, optional = true } hashlink = "0.7.0" indexmap = "1.7.0" + +[dev-dependencies] +sqlx = { version = "0.5.10", path = "..", features = ["postgres", "sqlite"] } \ No newline at end of file diff --git a/sqlx-core/src/acquire.rs b/sqlx-core/src/acquire.rs index 4a861d20b8..d03e708dbc 100644 --- a/sqlx-core/src/acquire.rs +++ b/sqlx-core/src/acquire.rs @@ -5,6 +5,67 @@ use crate::transaction::Transaction; use futures_core::future::BoxFuture; use std::ops::{Deref, DerefMut}; +/// Acquire connections or transactions from a database in a generic way. +/// +/// If you want to accept generic database connections that implement +/// [`Acquire`] which then allows you to [`acquire`][`Acquire::acquire`] a +/// connection or [`begin`][`Acquire::begin`] a transaction, then you can do it +/// like that: +/// +/// ```rust +/// # use sqlx::{Acquire, postgres::Postgres, error::BoxDynError}; +/// async fn run_query<'a, A>(conn: A) -> Result<(), BoxDynError> +/// where +/// A: Acquire<'a, Database = Postgres>, +/// { +/// let mut conn = conn.acquire().await?; +/// +/// sqlx::query!("SELECT 1 as v").fetch_one(&mut *conn).await?; +/// sqlx::query!("SELECT 2 as v").fetch_one(&mut *conn).await?; +/// +/// Ok(()) +/// } +/// ``` +/// +/// If you run into a lifetime error about "implementation of `sqlx::Acquire` is +/// not general enough", the [workaround] looks like this: +/// +/// ```rust +/// # use std::future::Future; +/// # use sqlx::{Acquire, postgres::Postgres, error::BoxDynError}; +/// fn run_query<'a, 'c, A>(conn: A) -> impl Future> + Send + 'a +/// where +/// A: Acquire<'c, Database = Postgres> + Send + 'a, +/// { +/// async move { +/// let mut conn = conn.acquire().await?; +/// +/// sqlx::query!("SELECT 1 as v").fetch_one(&mut *conn).await?; +/// sqlx::query!("SELECT 2 as v").fetch_one(&mut *conn).await?; +/// +/// Ok(()) +/// } +/// } +/// ``` +/// +/// However, if you really just want to accept both, a transaction or a +/// connection as an argument to a function, then it's easier to just accept a +/// mutable reference to a database connection like so: +/// +/// ```rust +/// # use sqlx::{postgres::PgConnection, error::BoxDynError}; +/// async fn run_query(conn: &mut PgConnection) -> Result<(), BoxDynError> { +/// sqlx::query!("SELECT 1 as v").fetch_one(&mut *conn).await?; +/// sqlx::query!("SELECT 2 as v").fetch_one(&mut *conn).await?; +/// +/// Ok(()) +/// } +/// ``` +/// +/// The downside of this approach is that you have to `acquire` a connection +/// from a pool first and can't directly pass the pool as argument. +/// +/// [workaround]: https://github.com/launchbadge/sqlx/issues/1015#issuecomment-767787777 pub trait Acquire<'c> { type Database: Database; diff --git a/sqlx-core/src/sqlite/options/mod.rs b/sqlx-core/src/sqlite/options/mod.rs index 3420273556..d66b2bcff5 100644 --- a/sqlx-core/src/sqlite/options/mod.rs +++ b/sqlx-core/src/sqlite/options/mod.rs @@ -36,7 +36,6 @@ use indexmap::IndexMap; /// # Example /// /// ```rust,no_run -/// # use sqlx_core as sqlx; /// # use sqlx_core::connection::ConnectOptions; /// # use sqlx_core::error::Error; /// use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode};