sqlx_core/
query.rs

1use std::marker::PhantomData;
2
3use either::Either;
4use futures_core::stream::BoxStream;
5use futures_util::{future, StreamExt, TryFutureExt, TryStreamExt};
6
7use crate::arguments::{Arguments, IntoArguments};
8use crate::database::{Database, HasStatementCache};
9use crate::encode::Encode;
10use crate::error::{BoxDynError, Error};
11use crate::executor::{Execute, Executor};
12use crate::statement::Statement;
13use crate::types::Type;
14
15/// A single SQL query as a prepared statement. Returned by [`query()`].
16#[must_use = "query must be executed to affect database"]
17pub struct Query<'q, DB: Database, A> {
18    pub(crate) statement: Either<&'q str, &'q DB::Statement<'q>>,
19    pub(crate) arguments: Option<Result<A, BoxDynError>>,
20    pub(crate) database: PhantomData<DB>,
21    pub(crate) persistent: bool,
22}
23
24/// A single SQL query that will map its results to an owned Rust type.
25///
26/// Executes as a prepared statement.
27///
28/// Returned by [`Query::try_map`], `query!()`, etc. Has most of the same methods as [`Query`] but
29/// the return types are changed to reflect the mapping. However, there is no equivalent of
30/// [`Query::execute`] as it doesn't make sense to map the result type and then ignore it.
31///
32/// [`Query::bind`] is also omitted; stylistically we recommend placing your `.bind()` calls
33/// before `.try_map()`. This is also to prevent adding superfluous binds to the result of
34/// `query!()` et al.
35#[must_use = "query must be executed to affect database"]
36pub struct Map<'q, DB: Database, F, A> {
37    inner: Query<'q, DB, A>,
38    mapper: F,
39}
40
41impl<'q, DB, A> Execute<'q, DB> for Query<'q, DB, A>
42where
43    DB: Database,
44    A: Send + IntoArguments<'q, DB>,
45{
46    #[inline]
47    fn sql(&self) -> &'q str {
48        match self.statement {
49            Either::Right(statement) => statement.sql(),
50            Either::Left(sql) => sql,
51        }
52    }
53
54    fn statement(&self) -> Option<&DB::Statement<'q>> {
55        match self.statement {
56            Either::Right(statement) => Some(statement),
57            Either::Left(_) => None,
58        }
59    }
60
61    #[inline]
62    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments<'q>>, BoxDynError> {
63        self.arguments
64            .take()
65            .transpose()
66            .map(|option| option.map(IntoArguments::into_arguments))
67    }
68
69    #[inline]
70    fn persistent(&self) -> bool {
71        self.persistent
72    }
73}
74
75impl<'q, DB: Database> Query<'q, DB, <DB as Database>::Arguments<'q>> {
76    /// Bind a value for use with this SQL query.
77    ///
78    /// If the number of times this is called does not match the number of bind parameters that
79    /// appear in the query (`?` for most SQL flavors, `$1 .. $N` for Postgres) then an error
80    /// will be returned when this query is executed.
81    ///
82    /// There is no validation that the value is of the type expected by the query. Most SQL
83    /// flavors will perform type coercion (Postgres will return a database error).
84    ///
85    /// If encoding the value fails, the error is stored and later surfaced when executing the query.
86    pub fn bind<T: 'q + Encode<'q, DB> + Type<DB>>(mut self, value: T) -> Self {
87        let Ok(arguments) = self.get_arguments() else {
88            return self;
89        };
90
91        let argument_number = arguments.len() + 1;
92        if let Err(error) = arguments.add(value) {
93            self.arguments = Some(Err(format!(
94                "Encoding argument ${argument_number} failed: {error}"
95            )
96            .into()));
97        }
98
99        self
100    }
101
102    /// Like [`Query::try_bind`] but immediately returns an error if encoding the value failed.
103    pub fn try_bind<T: 'q + Encode<'q, DB> + Type<DB>>(
104        &mut self,
105        value: T,
106    ) -> Result<(), BoxDynError> {
107        let arguments = self.get_arguments()?;
108
109        arguments.add(value)
110    }
111
112    fn get_arguments(&mut self) -> Result<&mut DB::Arguments<'q>, BoxDynError> {
113        let Some(Ok(arguments)) = self.arguments.as_mut().map(Result::as_mut) else {
114            return Err("A previous call to Query::bind produced an error"
115                .to_owned()
116                .into());
117        };
118
119        Ok(arguments)
120    }
121}
122
123impl<'q, DB, A> Query<'q, DB, A>
124where
125    DB: Database + HasStatementCache,
126{
127    /// If `true`, the statement will get prepared once and cached to the
128    /// connection's statement cache.
129    ///
130    /// If queried once with the flag set to `true`, all subsequent queries
131    /// matching the one with the flag will use the cached statement until the
132    /// cache is cleared.
133    ///
134    /// If `false`, the prepared statement will be closed after execution.
135    ///
136    /// Default: `true`.
137    pub fn persistent(mut self, value: bool) -> Self {
138        self.persistent = value;
139        self
140    }
141}
142
143impl<'q, DB, A: Send> Query<'q, DB, A>
144where
145    DB: Database,
146    A: 'q + IntoArguments<'q, DB>,
147{
148    /// Map each row in the result to another type.
149    ///
150    /// See [`try_map`](Query::try_map) for a fallible version of this method.
151    ///
152    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using
153    /// a [`FromRow`](super::from_row::FromRow) implementation.
154    #[inline]
155    pub fn map<F, O>(
156        self,
157        mut f: F,
158    ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result<O, Error> + Send, A>
159    where
160        F: FnMut(DB::Row) -> O + Send,
161        O: Unpin,
162    {
163        self.try_map(move |row| Ok(f(row)))
164    }
165
166    /// Map each row in the result to another type.
167    ///
168    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using
169    /// a [`FromRow`](super::from_row::FromRow) implementation.
170    #[inline]
171    pub fn try_map<F, O>(self, f: F) -> Map<'q, DB, F, A>
172    where
173        F: FnMut(DB::Row) -> Result<O, Error> + Send,
174        O: Unpin,
175    {
176        Map {
177            inner: self,
178            mapper: f,
179        }
180    }
181
182    /// Execute the query and return the total number of rows affected.
183    #[inline]
184    pub async fn execute<'e, 'c: 'e, E>(self, executor: E) -> Result<DB::QueryResult, Error>
185    where
186        'q: 'e,
187        A: 'e,
188        E: Executor<'c, Database = DB>,
189    {
190        executor.execute(self).await
191    }
192
193    /// Execute multiple queries and return the rows affected from each query, in a stream.
194    #[inline]
195    #[deprecated = "Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead. See https://github.com/launchbadge/sqlx/issues/3108 for discussion."]
196    pub async fn execute_many<'e, 'c: 'e, E>(
197        self,
198        executor: E,
199    ) -> BoxStream<'e, Result<DB::QueryResult, Error>>
200    where
201        'q: 'e,
202        A: 'e,
203        E: Executor<'c, Database = DB>,
204    {
205        executor.execute_many(self)
206    }
207
208    /// Execute the query and return the generated results as a stream.
209    #[inline]
210    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<DB::Row, Error>>
211    where
212        'q: 'e,
213        A: 'e,
214        E: Executor<'c, Database = DB>,
215    {
216        executor.fetch(self)
217    }
218
219    /// Execute multiple queries and return the generated results as a stream.
220    ///
221    /// For each query in the stream, any generated rows are returned first,
222    /// then the `QueryResult` with the number of rows affected.
223    #[inline]
224    #[deprecated = "Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead. See https://github.com/launchbadge/sqlx/issues/3108 for discussion."]
225    // TODO: we'll probably still want a way to get the `DB::QueryResult` at the end of a `fetch()` stream.
226    pub fn fetch_many<'e, 'c: 'e, E>(
227        self,
228        executor: E,
229    ) -> BoxStream<'e, Result<Either<DB::QueryResult, DB::Row>, Error>>
230    where
231        'q: 'e,
232        A: 'e,
233        E: Executor<'c, Database = DB>,
234    {
235        executor.fetch_many(self)
236    }
237
238    /// Execute the query and return all the resulting rows collected into a [`Vec`].
239    ///
240    /// ### Note: beware result set size.
241    /// This will attempt to collect the full result set of the query into memory.
242    ///
243    /// To avoid exhausting available memory, ensure the result set has a known upper bound,
244    /// e.g. using `LIMIT`.
245    #[inline]
246    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<DB::Row>, Error>
247    where
248        'q: 'e,
249        A: 'e,
250        E: Executor<'c, Database = DB>,
251    {
252        executor.fetch_all(self).await
253    }
254
255    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.
256    ///
257    /// ### Note: for best performance, ensure the query returns at most one row.
258    /// Depending on the driver implementation, if your query can return more than one row,
259    /// it may lead to wasted CPU time and bandwidth on the database server.
260    ///
261    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row
262    /// can result in a more optimal query plan.
263    ///
264    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.
265    ///
266    /// Otherwise, you might want to add `LIMIT 1` to your query.
267    #[inline]
268    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<DB::Row, Error>
269    where
270        'q: 'e,
271        A: 'e,
272        E: Executor<'c, Database = DB>,
273    {
274        executor.fetch_one(self).await
275    }
276
277    /// Execute the query, returning the first row or `None` otherwise.
278    ///
279    /// ### Note: for best performance, ensure the query returns at most one row.
280    /// Depending on the driver implementation, if your query can return more than one row,
281    /// it may lead to wasted CPU time and bandwidth on the database server.
282    ///
283    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row
284    /// can result in a more optimal query plan.
285    ///
286    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.
287    ///
288    /// Otherwise, you might want to add `LIMIT 1` to your query.
289    #[inline]
290    pub async fn fetch_optional<'e, 'c: 'e, E>(self, executor: E) -> Result<Option<DB::Row>, Error>
291    where
292        'q: 'e,
293        A: 'e,
294        E: Executor<'c, Database = DB>,
295    {
296        executor.fetch_optional(self).await
297    }
298}
299
300impl<'q, DB, F: Send, A: Send> Execute<'q, DB> for Map<'q, DB, F, A>
301where
302    DB: Database,
303    A: IntoArguments<'q, DB>,
304{
305    #[inline]
306    fn sql(&self) -> &'q str {
307        self.inner.sql()
308    }
309
310    #[inline]
311    fn statement(&self) -> Option<&DB::Statement<'q>> {
312        self.inner.statement()
313    }
314
315    #[inline]
316    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments<'q>>, BoxDynError> {
317        self.inner.take_arguments()
318    }
319
320    #[inline]
321    fn persistent(&self) -> bool {
322        self.inner.arguments.is_some()
323    }
324}
325
326impl<'q, DB, F, O, A> Map<'q, DB, F, A>
327where
328    DB: Database,
329    F: FnMut(DB::Row) -> Result<O, Error> + Send,
330    O: Send + Unpin,
331    A: 'q + Send + IntoArguments<'q, DB>,
332{
333    /// Map each row in the result to another type.
334    ///
335    /// See [`try_map`](Map::try_map) for a fallible version of this method.
336    ///
337    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using
338    /// a [`FromRow`](super::from_row::FromRow) implementation.
339    #[inline]
340    pub fn map<G, P>(
341        self,
342        mut g: G,
343    ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result<P, Error> + Send, A>
344    where
345        G: FnMut(O) -> P + Send,
346        P: Unpin,
347    {
348        self.try_map(move |data| Ok(g(data)))
349    }
350
351    /// Map each row in the result to another type.
352    ///
353    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using
354    /// a [`FromRow`](super::from_row::FromRow) implementation.
355    #[inline]
356    pub fn try_map<G, P>(
357        self,
358        mut g: G,
359    ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result<P, Error> + Send, A>
360    where
361        G: FnMut(O) -> Result<P, Error> + Send,
362        P: Unpin,
363    {
364        let mut f = self.mapper;
365        Map {
366            inner: self.inner,
367            mapper: move |row| f(row).and_then(&mut g),
368        }
369    }
370
371    /// Execute the query and return the generated results as a stream.
372    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<O, Error>>
373    where
374        'q: 'e,
375        E: 'e + Executor<'c, Database = DB>,
376        DB: 'e,
377        F: 'e,
378        O: 'e,
379    {
380        // FIXME: this should have used `executor.fetch()` but that's a breaking change
381        // because this technically allows multiple statements in one query string.
382        #[allow(deprecated)]
383        self.fetch_many(executor)
384            .try_filter_map(|step| async move {
385                Ok(match step {
386                    Either::Left(_) => None,
387                    Either::Right(o) => Some(o),
388                })
389            })
390            .boxed()
391    }
392
393    /// Execute multiple queries and return the generated results as a stream
394    /// from each query, in a stream.
395    #[deprecated = "Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead."]
396    pub fn fetch_many<'e, 'c: 'e, E>(
397        mut self,
398        executor: E,
399    ) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>
400    where
401        'q: 'e,
402        E: 'e + Executor<'c, Database = DB>,
403        DB: 'e,
404        F: 'e,
405        O: 'e,
406    {
407        Box::pin(try_stream! {
408            let mut s = executor.fetch_many(self.inner);
409
410            while let Some(v) = s.try_next().await? {
411                r#yield!(match v {
412                    Either::Left(v) => Either::Left(v),
413                    Either::Right(row) => {
414                        Either::Right((self.mapper)(row)?)
415                    }
416                });
417            }
418
419            Ok(())
420        })
421    }
422
423    /// Execute the query and return all the resulting rows collected into a [`Vec`].
424    ///
425    /// ### Note: beware result set size.
426    /// This will attempt to collect the full result set of the query into memory.
427    ///
428    /// To avoid exhausting available memory, ensure the result set has a known upper bound,
429    /// e.g. using `LIMIT`.
430    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<O>, Error>
431    where
432        'q: 'e,
433        E: 'e + Executor<'c, Database = DB>,
434        DB: 'e,
435        F: 'e,
436        O: 'e,
437    {
438        self.fetch(executor).try_collect().await
439    }
440
441    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.
442    ///
443    /// ### Note: for best performance, ensure the query returns at most one row.
444    /// Depending on the driver implementation, if your query can return more than one row,
445    /// it may lead to wasted CPU time and bandwidth on the database server.
446    ///
447    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row
448    /// can result in a more optimal query plan.
449    ///
450    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.
451    ///
452    /// Otherwise, you might want to add `LIMIT 1` to your query.
453    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<O, Error>
454    where
455        'q: 'e,
456        E: 'e + Executor<'c, Database = DB>,
457        DB: 'e,
458        F: 'e,
459        O: 'e,
460    {
461        self.fetch_optional(executor)
462            .and_then(|row| match row {
463                Some(row) => future::ok(row),
464                None => future::err(Error::RowNotFound),
465            })
466            .await
467    }
468
469    /// Execute the query, returning the first row or `None` otherwise.
470    ///
471    /// ### Note: for best performance, ensure the query returns at most one row.
472    /// Depending on the driver implementation, if your query can return more than one row,
473    /// it may lead to wasted CPU time and bandwidth on the database server.
474    ///
475    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row
476    /// can result in a more optimal query plan.
477    ///
478    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.
479    ///
480    /// Otherwise, you might want to add `LIMIT 1` to your query.
481    pub async fn fetch_optional<'e, 'c: 'e, E>(mut self, executor: E) -> Result<Option<O>, Error>
482    where
483        'q: 'e,
484        E: 'e + Executor<'c, Database = DB>,
485        DB: 'e,
486        F: 'e,
487        O: 'e,
488    {
489        let row = executor.fetch_optional(self.inner).await?;
490
491        if let Some(row) = row {
492            (self.mapper)(row).map(Some)
493        } else {
494            Ok(None)
495        }
496    }
497}
498
499/// Execute a single SQL query as a prepared statement (explicitly created).
500pub fn query_statement<'q, DB>(
501    statement: &'q DB::Statement<'q>,
502) -> Query<'q, DB, <DB as Database>::Arguments<'_>>
503where
504    DB: Database,
505{
506    Query {
507        database: PhantomData,
508        arguments: Some(Ok(Default::default())),
509        statement: Either::Right(statement),
510        persistent: true,
511    }
512}
513
514/// Execute a single SQL query as a prepared statement (explicitly created), with the given arguments.
515pub fn query_statement_with<'q, DB, A>(
516    statement: &'q DB::Statement<'q>,
517    arguments: A,
518) -> Query<'q, DB, A>
519where
520    DB: Database,
521    A: IntoArguments<'q, DB>,
522{
523    Query {
524        database: PhantomData,
525        arguments: Some(Ok(arguments)),
526        statement: Either::Right(statement),
527        persistent: true,
528    }
529}
530
531/// Execute a single SQL query as a prepared statement (transparently cached).
532///
533/// The query string may only contain a single DML statement: `SELECT`, `INSERT`, `UPDATE`, `DELETE` and variants.
534/// The SQLite driver does not currently follow this restriction, but that behavior is deprecated.
535///
536/// The connection will transparently prepare and cache the statement, which means it only needs to be parsed once
537/// in the connection's lifetime, and any generated query plans can be retained.
538/// Thus, the overhead of executing the statement is amortized.
539///
540/// Some third-party databases that speak a supported protocol, e.g. CockroachDB or PGBouncer that speak Postgres,
541/// may have issues with the transparent caching of prepared statements. If you are having trouble,
542/// try setting [`.persistent(false)`][Query::persistent].
543///
544/// See the [`Query`] type for the methods you may call.
545///
546/// ### Dynamic Input: Use Query Parameters (Prevents SQL Injection)
547/// At some point, you'll likely want to include some form of dynamic input in your query, possibly from the user.
548///
549/// Your first instinct might be to do something like this:
550/// ```rust,no_run
551/// # async fn example() -> sqlx::Result<()> {
552/// # let mut conn: sqlx::PgConnection = unimplemented!();
553/// // Imagine this is input from the user, e.g. a search form on a website.
554/// let user_input = "possibly untrustworthy input!";
555///
556/// // DO NOT DO THIS unless you're ABSOLUTELY CERTAIN it's what you need!
557/// let query = format!("SELECT * FROM articles WHERE content LIKE '%{user_input}%'");
558/// // where `conn` is `PgConnection` or `MySqlConnection`
559/// // or some other type that implements `Executor`.
560/// let results = sqlx::query(&query).fetch_all(&mut conn).await?;
561/// # Ok(())
562/// # }
563/// ```
564///
565/// The example above showcases a **SQL injection vulnerability**, because it's trivial for a malicious user to craft
566/// an input that can "break out" of the string literal.
567///
568/// For example, if they send the input `foo'; DELETE FROM articles; --`
569/// then your application would send the following to the database server (line breaks added for clarity):
570///
571/// ```sql
572/// SELECT * FROM articles WHERE content LIKE '%foo';
573/// DELETE FROM articles;
574/// --%'
575/// ```
576///
577/// In this case, because this interface *always* uses prepared statements, you would likely be fine because prepared
578/// statements _generally_ (see above) are only allowed to contain a single query. This would simply return an error.
579///
580/// However, it would also break on legitimate user input.
581/// What if someone wanted to search for the string `Alice's Apples`? It would also return an error because
582/// the database would receive a query with a broken string literal (line breaks added for clarity):
583///
584/// ```sql
585/// SELECT * FROM articles WHERE content LIKE '%Alice'
586/// s Apples%'
587/// ```
588///
589/// Of course, it's possible to make this syntactically valid by escaping the apostrophe, but there's a better way.
590///
591/// ##### You should always prefer query parameters for dynamic input.
592///
593/// When using query parameters, you add placeholders to your query where a value
594/// should be substituted at execution time, then call [`.bind()`][Query::bind] with that value.
595///
596/// The syntax for placeholders is unfortunately not standardized and depends on the database:
597///
598/// * Postgres and SQLite: use `$1`, `$2`, `$3`, etc.
599///     * The number is the Nth bound value, starting from one.
600///     * The same placeholder can be used arbitrarily many times to refer to the same bound value.
601///     * SQLite technically supports MySQL's syntax as well as others, but we recommend using this syntax
602///       as SQLx's SQLite driver is written with it in mind.
603/// * MySQL and MariaDB: use `?`.
604///     * Placeholders are purely positional, similar to `println!("{}, {}", foo, bar)`.
605///     * The order of bindings must match the order of placeholders in the query.
606///     * To use a value in multiple places, you must bind it multiple times.
607///
608/// In both cases, the placeholder syntax acts as a variable expression representing the bound value:
609///
610/// ```rust,no_run
611/// # async fn example2() -> sqlx::Result<()> {
612/// # let mut conn: sqlx::PgConnection = unimplemented!();
613/// let user_input = "Alice's Apples";
614///
615/// // Postgres and SQLite
616/// let results = sqlx::query(
617///     // Notice how we only have to bind the argument once and we can use it multiple times:
618///     "SELECT * FROM articles
619///      WHERE title LIKE '%' || $1 || '%'
620///      OR content LIKE '%' || $1 || '%'"
621/// )
622///     .bind(user_input)
623///     .fetch_all(&mut conn)
624///     .await?;
625///
626/// // MySQL and MariaDB
627/// let results = sqlx::query(
628///     "SELECT * FROM articles
629///      WHERE title LIKE CONCAT('%', ?, '%')
630///      OR content LIKE CONCAT('%', ?, '%')"
631/// )
632///     // If we want to reference the same value multiple times, we have to bind it multiple times:
633///     .bind(user_input)
634///     .bind(user_input)
635///     .fetch_all(&mut conn)
636///     .await?;
637/// # Ok(())
638/// # }
639/// ```
640/// ##### The value bound to a query parameter is entirely separate from the query and does not affect its syntax.
641/// Thus, SQL injection is impossible (barring shenanigans like calling a SQL function that lets you execute a string
642/// as a statement) and *all* strings are valid.
643///
644/// This also means you cannot use query parameters to add conditional SQL fragments.
645///
646/// **SQLx does not substitute placeholders on the client side**. It is done by the database server itself.
647///
648/// ##### SQLx supports many different types for parameter binding, not just strings.
649/// Any type that implements [`Encode<DB>`][Encode] and [`Type<DB>`] can be bound as a parameter.
650///
651/// See [the `types` module][crate::types] (links to `sqlx_core::types` but you should use `sqlx::types`) for details.
652///
653/// As an additional benefit, query parameters are usually sent in a compact binary encoding instead of a human-readable
654/// text encoding, which saves bandwidth.
655pub fn query<DB>(sql: &str) -> Query<'_, DB, <DB as Database>::Arguments<'_>>
656where
657    DB: Database,
658{
659    Query {
660        database: PhantomData,
661        arguments: Some(Ok(Default::default())),
662        statement: Either::Left(sql),
663        persistent: true,
664    }
665}
666
667/// Execute a SQL query as a prepared statement (transparently cached), with the given arguments.
668///
669/// See [`query()`][query] for details, such as supported syntax.
670pub fn query_with<'q, DB, A>(sql: &'q str, arguments: A) -> Query<'q, DB, A>
671where
672    DB: Database,
673    A: IntoArguments<'q, DB>,
674{
675    query_with_result(sql, Ok(arguments))
676}
677
678/// Same as [`query_with`] but is initialized with a Result of arguments instead
679pub fn query_with_result<'q, DB, A>(
680    sql: &'q str,
681    arguments: Result<A, BoxDynError>,
682) -> Query<'q, DB, A>
683where
684    DB: Database,
685    A: IntoArguments<'q, DB>,
686{
687    Query {
688        database: PhantomData,
689        arguments: Some(arguments),
690        statement: Either::Left(sql),
691        persistent: true,
692    }
693}