cdbc/
query_scalar.rs

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