sqlx_core/
query_as.rs

1use std::marker::PhantomData;
2
3use either::Either;
4use futures_core::stream::BoxStream;
5use futures_util::{StreamExt, TryStreamExt};
6
7use crate::arguments::IntoArguments;
8use crate::database::{Database, HasStatementCache};
9use crate::encode::Encode;
10use crate::error::{BoxDynError, Error};
11use crate::executor::{Execute, Executor};
12use crate::from_row::FromRow;
13use crate::query::{query, query_statement, query_statement_with, query_with_result, Query};
14use crate::sql_str::{SqlSafeStr, SqlStr};
15use crate::types::Type;
16
17/// A single SQL query as a prepared statement, mapping results using [`FromRow`].
18/// Returned by [`query_as()`].
19#[must_use = "query must be executed to affect database"]
20pub struct QueryAs<'q, DB: Database, O, A> {
21    pub(crate) inner: Query<'q, DB, A>,
22    pub(crate) output: PhantomData<O>,
23}
24
25impl<'q, DB, O: Send, A: Send> Execute<'q, DB> for QueryAs<'q, DB, O, A>
26where
27    DB: Database,
28    A: 'q + IntoArguments<DB>,
29{
30    #[inline]
31    fn sql(self) -> SqlStr {
32        self.inner.sql()
33    }
34
35    #[inline]
36    fn statement(&self) -> Option<&DB::Statement> {
37        self.inner.statement()
38    }
39
40    #[inline]
41    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {
42        self.inner.take_arguments()
43    }
44
45    #[inline]
46    fn persistent(&self) -> bool {
47        self.inner.persistent()
48    }
49}
50
51impl<'q, DB: Database, O> QueryAs<'q, DB, O, <DB as Database>::Arguments> {
52    /// Bind a value for use with this SQL query.
53    ///
54    /// See [`Query::bind`](Query::bind).
55    pub fn bind<T: 'q + Encode<'q, DB> + Type<DB>>(mut self, value: T) -> Self {
56        self.inner = self.inner.bind(value);
57        self
58    }
59}
60
61impl<DB, O, A> QueryAs<'_, DB, O, A>
62where
63    DB: Database + HasStatementCache,
64{
65    /// If `true`, the statement will get prepared once and cached to the
66    /// connection's statement cache.
67    ///
68    /// If queried once with the flag set to `true`, all subsequent queries
69    /// matching the one with the flag will use the cached statement until the
70    /// cache is cleared.
71    ///
72    /// If `false`, the prepared statement will be closed after execution.
73    ///
74    /// Default: `true`.
75    pub fn persistent(mut self, value: bool) -> Self {
76        self.inner = self.inner.persistent(value);
77        self
78    }
79}
80
81// FIXME: This is very close, nearly 1:1 with `Map`
82// noinspection DuplicatedCode
83impl<'q, DB, O, A> QueryAs<'q, DB, O, A>
84where
85    DB: Database,
86    A: 'q + IntoArguments<DB>,
87    O: Send + Unpin + for<'r> FromRow<'r, DB::Row>,
88{
89    /// Execute the query and return the generated results as a stream.
90    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<O, Error>>
91    where
92        'q: 'e,
93        E: 'e + Executor<'c, Database = DB>,
94        DB: 'e,
95        O: 'e,
96        A: 'e,
97    {
98        executor
99            .fetch(self.inner)
100            .map(|row| O::from_row(&row?))
101            .boxed()
102    }
103
104    /// Execute multiple queries and return the generated results as a stream
105    /// from each query, in a stream.
106    #[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."]
107    pub fn fetch_many<'e, 'c: 'e, E>(
108        self,
109        executor: E,
110    ) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>
111    where
112        'q: 'e,
113        E: 'e + Executor<'c, Database = DB>,
114        DB: 'e,
115        O: 'e,
116        A: 'e,
117    {
118        executor
119            .fetch_many(self.inner)
120            .map(|v| match v {
121                Ok(Either::Right(row)) => O::from_row(&row).map(Either::Right),
122                Ok(Either::Left(v)) => Ok(Either::Left(v)),
123                Err(e) => Err(e),
124            })
125            .boxed()
126    }
127
128    /// Execute the query and return all the resulting rows collected into a [`Vec`].
129    ///
130    /// ### Note: beware result set size.
131    /// This will attempt to collect the full result set of the query into memory.
132    ///
133    /// To avoid exhausting available memory, ensure the result set has a known upper bound,
134    /// e.g. using `LIMIT`.
135    #[inline]
136    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<O>, Error>
137    where
138        'q: 'e,
139        E: 'e + Executor<'c, Database = DB>,
140        DB: 'e,
141        O: 'e,
142        A: 'e,
143    {
144        self.fetch(executor).try_collect().await
145    }
146
147    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.
148    ///
149    /// ### Note: for best performance, ensure the query returns at most one row.
150    /// Depending on the driver implementation, if your query can return more than one row,
151    /// it may lead to wasted CPU time and bandwidth on the database server.
152    ///
153    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row
154    /// can result in a more optimal query plan.
155    ///
156    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.
157    ///
158    /// Otherwise, you might want to add `LIMIT 1` to your query.
159    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<O, Error>
160    where
161        'q: 'e,
162        E: 'e + Executor<'c, Database = DB>,
163        DB: 'e,
164        O: 'e,
165        A: 'e,
166    {
167        self.fetch_optional(executor)
168            .await
169            .and_then(|row| row.ok_or(Error::RowNotFound))
170    }
171
172    /// Execute the query, returning the first row or `None` otherwise.
173    ///
174    /// ### Note: for best performance, ensure the query returns at most one row.
175    /// Depending on the driver implementation, if your query can return more than one row,
176    /// it may lead to wasted CPU time and bandwidth on the database server.
177    ///
178    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row
179    /// can result in a more optimal query plan.
180    ///
181    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.
182    ///
183    /// Otherwise, you might want to add `LIMIT 1` to your query.
184    pub async fn fetch_optional<'e, 'c: 'e, E>(self, executor: E) -> Result<Option<O>, Error>
185    where
186        'q: 'e,
187        E: 'e + Executor<'c, Database = DB>,
188        DB: 'e,
189        O: 'e,
190        A: 'e,
191    {
192        let row = executor.fetch_optional(self.inner).await?;
193        if let Some(row) = row {
194            O::from_row(&row).map(Some)
195        } else {
196            Ok(None)
197        }
198    }
199}
200
201/// Execute a single SQL query as a prepared statement (transparently cached).
202/// Maps rows to Rust types using [`FromRow`].
203///
204/// For details about prepared statements and allowed SQL syntax, see [`query()`][crate::query::query].
205///
206/// ### Example: Map Rows using Tuples
207/// [`FromRow`] is implemented for tuples of up to 16 elements<sup>1</sup>.
208/// Using a tuple of N elements will extract the first N columns from each row using [`Decode`][crate::decode::Decode].
209/// Any extra columns are ignored.
210///
211/// See [`sqlx::types`][crate::types] for the types that can be used.
212///
213/// The `FromRow` implementation will check [`Type::compatible()`] for each column to ensure a compatible type mapping
214/// is used. If an incompatible mapping is detected, an error is returned.
215/// To statically assert compatible types at compile time, see the `query!()` family of macros.
216///
217/// **NOTE**: `SELECT *` is not recommended with this approach because the ordering of returned columns may be different
218/// than expected, especially when using joins.
219///
220/// ```rust,no_run
221/// # async fn example1() -> sqlx::Result<()> {
222/// use sqlx::Connection;
223/// use sqlx::PgConnection;
224///
225/// // This example can be applied to any database as it only uses standard types and syntax.
226/// let mut conn: PgConnection = PgConnection::connect("<Database URL>").await?;
227///
228/// sqlx::raw_sql(
229///     "CREATE TABLE users(id INTEGER PRIMARY KEY, username TEXT UNIQUE, created_at TIMESTAMPTZ DEFAULT (now()))"
230/// )
231///     .execute(&mut conn)
232///     .await?;
233///
234/// sqlx::query("INSERT INTO users(id, username) VALUES (1, 'alice'), (2, 'bob');")
235///     .execute(&mut conn)
236///     .await?;
237///
238/// // Get the first row of the result (note the `LIMIT 1` for efficiency)
239/// // This assumes the `time` feature of SQLx is enabled.
240/// let oldest_user: (i32, String, time::OffsetDateTime) = sqlx::query_as(
241///     "SELECT id, username, created_at FROM users ORDER BY created_at LIMIT 1"
242/// )
243///     .fetch_one(&mut conn)
244///     .await?;
245///
246/// assert_eq!(oldest_user.0, 1);
247/// assert_eq!(oldest_user.1, "alice");
248///
249/// // Get at most one row
250/// let maybe_charlie: Option<(i32, String, time::OffsetDateTime)> = sqlx::query_as(
251///     "SELECT id, username, created_at FROM users WHERE username = 'charlie'"
252/// )
253///     .fetch_optional(&mut conn)
254///     .await?;
255///
256/// assert_eq!(maybe_charlie, None);
257///
258/// // Get all rows in result (Beware of the size of the result set! Consider using `LIMIT`)
259/// let users: Vec<(i32, String, time::OffsetDateTime)> = sqlx::query_as(
260///     "SELECT id, username, created_at FROM users ORDER BY id"
261/// )
262///     .fetch_all(&mut conn)
263///     .await?;
264///
265/// println!("{users:?}");
266/// # Ok(())
267/// # }
268/// ```
269///
270/// <sup>1</sup>: It's impossible in Rust to implement a trait for tuples of arbitrary size.
271/// For larger result sets, either use an explicit struct (see below) or use [`query()`][crate::query::query]
272/// instead and extract columns dynamically.
273///
274/// ### Example: Map Rows using `#[derive(FromRow)]`
275/// Using `#[derive(FromRow)]`, we can create a Rust struct to represent our row type
276/// so we can look up fields by name instead of tuple index.
277///
278/// When querying this way, columns will be matched up to the corresponding fields by name, so `SELECT *` is safe to use.
279/// However, you will still want to be aware of duplicate column names in your query when using joins.
280///
281/// The derived `FromRow` implementation will check [`Type::compatible()`] for each column to ensure a compatible type
282/// mapping is used. If an incompatible mapping is detected, an error is returned.
283/// To statically assert compatible types at compile time, see the `query!()` family of macros.
284///
285/// An error will also be returned if an expected column is missing from the result set.
286///
287/// `#[derive(FromRow)]` supports several control attributes which can be used to change how column names and types
288/// are mapped. See [`FromRow`] for details.
289///
290/// Using our previous table definition, we can convert our queries like so:
291/// ```rust,no_run
292/// # async fn example2() -> sqlx::Result<()> {
293/// use sqlx::Connection;
294/// use sqlx::PgConnection;
295///
296/// use time::OffsetDateTime;
297///
298/// #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]
299/// struct User {
300///     id: i64,
301///     username: String,
302///     // Note: the derive won't compile if the `time` feature of SQLx is not enabled.
303///     created_at: OffsetDateTime,
304/// }
305///
306/// let mut conn: PgConnection = PgConnection::connect("<Database URL>").await?;
307///
308/// // Get the first row of the result (note the `LIMIT 1` for efficiency)
309/// let oldest_user: User = sqlx::query_as(
310///     "SELECT id, username, created_at FROM users ORDER BY created_at LIMIT 1"
311/// )
312///     .fetch_one(&mut conn)
313///     .await?;
314///
315/// assert_eq!(oldest_user.id, 1);
316/// assert_eq!(oldest_user.username, "alice");
317///
318/// // Get at most one row
319/// let maybe_charlie: Option<User> = sqlx::query_as(
320///     "SELECT id, username, created_at FROM users WHERE username = 'charlie'"
321/// )
322///     .fetch_optional(&mut conn)
323///     .await?;
324///
325/// assert_eq!(maybe_charlie, None);
326///
327/// // Get all rows in result (Beware of the size of the result set! Consider using `LIMIT`)
328/// let users: Vec<User> = sqlx::query_as(
329///     "SELECT id, username, created_at FROM users ORDER BY id"
330/// )
331///     .fetch_all(&mut conn)
332///     .await?;
333///
334/// assert_eq!(users[1].id, 2);
335/// assert_eq!(users[1].username, "bob");
336/// # Ok(())
337/// # }
338///
339/// ```
340#[inline]
341pub fn query_as<'q, DB, O>(sql: impl SqlSafeStr) -> QueryAs<'q, DB, O, <DB as Database>::Arguments>
342where
343    DB: Database,
344    O: for<'r> FromRow<'r, DB::Row>,
345{
346    QueryAs {
347        inner: query(sql),
348        output: PhantomData,
349    }
350}
351
352/// Execute a single SQL query, with the given arguments as a prepared statement (transparently cached).
353/// Maps rows to Rust types using [`FromRow`].
354///
355/// For details about prepared statements and allowed SQL syntax, see [`query()`][crate::query::query].
356///
357/// For details about type mapping from [`FromRow`], see [`query_as()`].
358#[inline]
359pub fn query_as_with<'q, DB, O, A>(sql: impl SqlSafeStr, arguments: A) -> QueryAs<'q, DB, O, A>
360where
361    DB: Database,
362    A: IntoArguments<DB>,
363    O: for<'r> FromRow<'r, DB::Row>,
364{
365    query_as_with_result(sql, Ok(arguments))
366}
367
368/// Same as [`query_as_with`] but takes arguments as a Result
369#[inline]
370pub fn query_as_with_result<'q, DB, O, A>(
371    sql: impl SqlSafeStr,
372    arguments: Result<A, BoxDynError>,
373) -> QueryAs<'q, DB, O, A>
374where
375    DB: Database,
376    A: IntoArguments<DB>,
377    O: for<'r> FromRow<'r, DB::Row>,
378{
379    QueryAs {
380        inner: query_with_result(sql, arguments),
381        output: PhantomData,
382    }
383}
384
385// Make a SQL query from a statement, that is mapped to a concrete type.
386pub fn query_statement_as<DB, O>(
387    statement: &DB::Statement,
388) -> QueryAs<'_, DB, O, <DB as Database>::Arguments>
389where
390    DB: Database,
391    O: for<'r> FromRow<'r, DB::Row>,
392{
393    QueryAs {
394        inner: query_statement(statement),
395        output: PhantomData,
396    }
397}
398
399// Make a SQL query from a statement, with the given arguments, that is mapped to a concrete type.
400pub fn query_statement_as_with<'q, DB, O, A>(
401    statement: &'q DB::Statement,
402    arguments: A,
403) -> QueryAs<'q, DB, O, A>
404where
405    DB: Database,
406    A: IntoArguments<DB>,
407    O: for<'r> FromRow<'r, DB::Row>,
408{
409    QueryAs {
410        inner: query_statement_with(statement, arguments),
411        output: PhantomData,
412    }
413}