diff --git a/sqlx-core/src/executor.rs b/sqlx-core/src/executor.rs index 84b1a660d8..5a3c48d121 100644 --- a/sqlx-core/src/executor.rs +++ b/sqlx-core/src/executor.rs @@ -1,3 +1,4 @@ +use crate::arguments::IntoArguments; use crate::database::Database; use crate::describe::Describe; use crate::error::{BoxDynError, Error}; @@ -210,6 +211,16 @@ pub trait Execute<'q, DB: Database>: Send + Sized { fn persistent(&self) -> bool; } +pub trait ExecuteEx<'q, DB: Database, A: IntoArguments<'q, DB>>: Execute<'q, DB> { + /// Replaces the arguments to be bound against the query string. + /// + /// See [`Execute::take_arguments`] for the return value considerations + fn replace_arguments( + &mut self, + arguments: A, + ) -> Result::Arguments<'q>>, BoxDynError>; +} + // NOTE: `Execute` is explicitly not implemented for String and &String to make it slightly more // involved to write `conn.execute(format!("SELECT {val}"))` impl<'q, DB: Database> Execute<'q, DB> for &'q str { @@ -255,3 +266,15 @@ impl<'q, DB: Database> Execute<'q, DB> for (&'q str, Option<::Ar true } } + +impl<'q, DB: Database, A: IntoArguments<'q, DB>> ExecuteEx<'q, DB, A> + for (&'q str, Option<::Arguments<'q>>) +{ + #[inline] + fn replace_arguments( + &mut self, + arguments: A, + ) -> Result::Arguments<'q>>, BoxDynError> { + Ok(self.1.replace(arguments.into_arguments())) + } +} diff --git a/sqlx-core/src/query.rs b/sqlx-core/src/query.rs index 60f509c342..a6cb4f691e 100644 --- a/sqlx-core/src/query.rs +++ b/sqlx-core/src/query.rs @@ -8,7 +8,7 @@ use crate::arguments::{Arguments, IntoArguments}; use crate::database::{Database, HasStatementCache}; use crate::encode::Encode; use crate::error::{BoxDynError, Error}; -use crate::executor::{Execute, Executor}; +use crate::executor::{Execute, ExecuteEx, Executor}; use crate::statement::Statement; use crate::types::Type; @@ -72,6 +72,23 @@ where } } +impl<'q, DB, A> ExecuteEx<'q, DB, A> for Query<'q, DB, A> +where + DB: Database, + A: Send + IntoArguments<'q, DB>, +{ + #[inline] + fn replace_arguments( + &mut self, + arguments: A, + ) -> Result::Arguments<'q>>, BoxDynError> { + self.arguments + .replace(Ok(arguments)) + .transpose() + .map(|option| option.map(IntoArguments::into_arguments)) + } +} + impl<'q, DB: Database> Query<'q, DB, ::Arguments<'q>> { /// Bind a value for use with this SQL query. /// @@ -323,6 +340,20 @@ where } } +impl<'q, DB, F: Send, A: Send> ExecuteEx<'q, DB, A> for Map<'q, DB, F, A> +where + DB: Database, + A: IntoArguments<'q, DB>, +{ + #[inline] + fn replace_arguments( + &mut self, + arguments: A, + ) -> Result::Arguments<'q>>, BoxDynError> { + self.inner.replace_arguments(arguments) + } +} + impl<'q, DB, F, O, A> Map<'q, DB, F, A> where DB: Database, diff --git a/sqlx-core/src/query_as.rs b/sqlx-core/src/query_as.rs index 9f28fe41e9..07f28e8c16 100644 --- a/sqlx-core/src/query_as.rs +++ b/sqlx-core/src/query_as.rs @@ -8,7 +8,7 @@ use crate::arguments::IntoArguments; use crate::database::{Database, HasStatementCache}; use crate::encode::Encode; use crate::error::{BoxDynError, Error}; -use crate::executor::{Execute, Executor}; +use crate::executor::{Execute, ExecuteEx, Executor}; use crate::from_row::FromRow; use crate::query::{query, query_statement, query_statement_with, query_with_result, Query}; use crate::types::Type; @@ -47,6 +47,20 @@ where } } +impl<'q, DB, O: Send, A: Send> ExecuteEx<'q, DB, A> for QueryAs<'q, DB, O, A> +where + DB: Database, + A: 'q + IntoArguments<'q, DB>, +{ + #[inline] + fn replace_arguments( + &mut self, + arguments: A, + ) -> Result::Arguments<'q>>, BoxDynError> { + self.inner.replace_arguments(arguments) + } +} + impl<'q, DB: Database, O> QueryAs<'q, DB, O, ::Arguments<'q>> { /// Bind a value for use with this SQL query. /// diff --git a/sqlx-core/src/query_scalar.rs b/sqlx-core/src/query_scalar.rs index c131adcca3..6f9fc07979 100644 --- a/sqlx-core/src/query_scalar.rs +++ b/sqlx-core/src/query_scalar.rs @@ -6,7 +6,7 @@ use crate::arguments::IntoArguments; use crate::database::{Database, HasStatementCache}; use crate::encode::Encode; use crate::error::{BoxDynError, Error}; -use crate::executor::{Execute, Executor}; +use crate::executor::{Execute, ExecuteEx, Executor}; use crate::from_row::FromRow; use crate::query_as::{ query_as, query_as_with_result, query_statement_as, query_statement_as_with, QueryAs, @@ -44,6 +44,20 @@ where } } +impl<'q, DB, O: Send, A: Send> ExecuteEx<'q, DB, A> for QueryScalar<'q, DB, O, A> +where + DB: Database, + A: 'q + IntoArguments<'q, DB>, +{ + #[inline] + fn replace_arguments( + &mut self, + arguments: A, + ) -> Result::Arguments<'q>>, BoxDynError> { + self.inner.replace_arguments(arguments) + } +} + impl<'q, DB: Database, O> QueryScalar<'q, DB, O, ::Arguments<'q>> { /// Bind a value for use with this SQL query. ///