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