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}