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#[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 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 pub fn persistent(mut self, value: bool) -> Self {
70 self.inner = self.inner.persistent(value);
71 self
72 }
73}
74
75impl<'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 #[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 #[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 #[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 #[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 #[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#[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#[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
190pub(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
203pub(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}