sqlx_core_oldapi/
query_scalar.rs

1use either::Either;
2use futures_core::stream::BoxStream;
3use futures_util::{StreamExt, TryFutureExt, TryStreamExt};
4
5use crate::arguments::IntoArguments;
6use crate::database::{Database, HasArguments, HasStatement, HasStatementCache};
7use crate::encode::Encode;
8use crate::error::Error;
9use crate::executor::{Execute, Executor};
10use crate::from_row::FromRow;
11use crate::query_as::{
12    query_as, query_as_with, query_statement_as, query_statement_as_with, QueryAs,
13};
14use crate::types::Type;
15
16/// Raw SQL query with bind parameters, mapped to a concrete type using [`FromRow`] on `(O,)`.
17/// Returned from [`query_scalar`].
18#[must_use = "query must be executed to affect database"]
19pub struct QueryScalar<'q, DB: Database, O, A> {
20    inner: QueryAs<'q, DB, (O,), A>,
21}
22
23impl<'q, DB: Database, O: Send, A: Send> Execute<'q, DB> for QueryScalar<'q, DB, O, A>
24where
25    A: 'q + IntoArguments<'q, DB>,
26{
27    #[inline]
28    fn sql(&self) -> &'q str {
29        self.inner.sql()
30    }
31
32    fn statement(&self) -> Option<&<DB as HasStatement<'q>>::Statement> {
33        self.inner.statement()
34    }
35
36    #[inline]
37    fn take_arguments(&mut self) -> Option<<DB as HasArguments<'q>>::Arguments> {
38        self.inner.take_arguments()
39    }
40
41    #[inline]
42    fn persistent(&self) -> bool {
43        self.inner.persistent()
44    }
45}
46
47impl<'q, DB: Database, O> QueryScalar<'q, DB, O, <DB as HasArguments<'q>>::Arguments> {
48    /// Bind a value for use with this SQL query.
49    ///
50    /// See [`Query::bind`](crate::query::Query::bind).
51    pub fn bind<T: 'q + Send + Encode<'q, DB> + Type<DB>>(mut self, value: T) -> Self {
52        self.inner = self.inner.bind(value);
53        self
54    }
55}
56
57impl<'q, DB, O, A> QueryScalar<'q, DB, O, A>
58where
59    DB: Database + HasStatementCache,
60{
61    /// If `true`, the statement will get prepared once and cached to the
62    /// connection's statement cache.
63    ///
64    /// If queried once with the flag set to `true`, all subsequent queries
65    /// matching the one with the flag will use the cached statement until the
66    /// cache is cleared.
67    ///
68    /// Default: `true`.
69    pub fn persistent(mut self, value: bool) -> Self {
70        self.inner = self.inner.persistent(value);
71        self
72    }
73}
74
75// FIXME: This is very close, nearly 1:1 with `Map`
76// noinspection DuplicatedCode
77impl<'q, DB, O, A> QueryScalar<'q, DB, O, A>
78where
79    DB: Database,
80    O: Send + Unpin,
81    A: 'q + IntoArguments<'q, DB>,
82    (O,): Send + Unpin + for<'r> FromRow<'r, DB::Row>,
83{
84    /// Execute the query and return the generated results as a stream.
85    #[inline]
86    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<O, Error>>
87    where
88        'q: 'e,
89        E: 'e + Executor<'c, Database = DB>,
90        DB: 'e,
91        A: 'e,
92        O: 'e,
93    {
94        self.inner.fetch(executor).map_ok(|it| it.0).boxed()
95    }
96
97    /// Execute multiple queries and return the generated results as a stream
98    /// from each query, in a stream.
99    #[inline]
100    pub fn fetch_many<'e, 'c: 'e, E>(
101        self,
102        executor: E,
103    ) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>
104    where
105        'q: 'e,
106        E: 'e + Executor<'c, Database = DB>,
107        DB: 'e,
108        A: 'e,
109        O: 'e,
110    {
111        self.inner
112            .fetch_many(executor)
113            .map_ok(|v| v.map_right(|it| it.0))
114            .boxed()
115    }
116
117    /// Execute the query and return all the generated results, collected into a [`Vec`].
118    #[inline]
119    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<O>, Error>
120    where
121        'q: 'e,
122        E: 'e + Executor<'c, Database = DB>,
123        DB: 'e,
124        (O,): 'e,
125        A: 'e,
126    {
127        self.inner
128            .fetch(executor)
129            .map_ok(|it| it.0)
130            .try_collect()
131            .await
132    }
133
134    /// Execute the query and returns exactly one row.
135    #[inline]
136    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<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.inner.fetch_one(executor).map_ok(|it| it.0).await
145    }
146
147    /// Execute the query and returns at most one row.
148    #[inline]
149    pub async fn fetch_optional<'e, 'c: 'e, E>(self, executor: E) -> Result<Option<O>, Error>
150    where
151        'q: 'e,
152        E: 'e + Executor<'c, Database = DB>,
153        DB: 'e,
154        O: 'e,
155        A: 'e,
156    {
157        Ok(self.inner.fetch_optional(executor).await?.map(|it| it.0))
158    }
159}
160
161/// Make a SQL query that is mapped to a single concrete type
162/// using [`FromRow`].
163#[inline]
164pub fn query_scalar<'q, DB, O>(
165    sql: &'q str,
166) -> QueryScalar<'q, DB, O, <DB as HasArguments<'q>>::Arguments>
167where
168    DB: Database,
169    (O,): for<'r> FromRow<'r, DB::Row>,
170{
171    QueryScalar {
172        inner: query_as(sql),
173    }
174}
175
176/// Make a SQL query, with the given arguments, that is mapped to a single concrete type
177/// using [`FromRow`].
178#[inline]
179pub fn query_scalar_with<'q, DB, O, A>(sql: &'q str, arguments: A) -> QueryScalar<'q, DB, O, A>
180where
181    DB: Database,
182    A: IntoArguments<'q, DB>,
183    (O,): for<'r> FromRow<'r, DB::Row>,
184{
185    QueryScalar {
186        inner: query_as_with(sql, arguments),
187    }
188}
189
190// Make a SQL query from a statement, that is mapped to a concrete value.
191pub(crate) fn query_statement_scalar<'q, DB, O>(
192    statement: &'q <DB as HasStatement<'q>>::Statement,
193) -> QueryScalar<'q, DB, O, <DB as HasArguments<'q>>::Arguments>
194where
195    DB: Database,
196    (O,): for<'r> FromRow<'r, DB::Row>,
197{
198    QueryScalar {
199        inner: query_statement_as(statement),
200    }
201}
202
203// Make a SQL query from a statement, with the given arguments, that is mapped to a concrete value.
204pub(crate) fn query_statement_scalar_with<'q, DB, O, A>(
205    statement: &'q <DB as HasStatement<'q>>::Statement,
206    arguments: A,
207) -> QueryScalar<'q, DB, O, A>
208where
209    DB: Database,
210    A: IntoArguments<'q, DB>,
211    (O,): for<'r> FromRow<'r, DB::Row>,
212{
213    QueryScalar {
214        inner: query_statement_as_with(statement, arguments),
215    }
216}