Skip to main content

sqlx_cloudflare_do/
executor.rs

1use std::future;
2
3use futures_core::future::BoxFuture;
4use futures_core::stream::BoxStream;
5use futures_util::{stream, FutureExt, StreamExt, TryFutureExt};
6use sqlx_core::describe::Describe;
7use sqlx_core::error::Error;
8use sqlx_core::executor::{Execute, Executor};
9use sqlx_core::sql_str::SqlStr;
10use sqlx_core::Either;
11
12use crate::error::unsupported;
13use crate::{
14    js, Do, DoArguments, DoConnection, DoQueryResult, DoRow, DoStatement, DoTransaction, DoTypeInfo,
15};
16
17// `sql.exec` is synchronous, so each future here finishes on its first poll
18// and holds nothing across an `await` -- which is why none of them needs
19// D1's `SendFuture`: they are `Send` because `DoConnection` and
20// `DoTransaction` are `Sync`. They still run the query when polled, not when
21// built, as sqlx's futures do.
22//
23// One implementation for both executors, a connection and an open transaction:
24// each only needs its `sql` handle, and a macro writes the impls for each.
25macro_rules! impl_executor {
26    ($ty:ty) => {
27        impl<'c> Executor<'c> for &'c $ty {
28            type Database = Do;
29
30            /// Reports `rows_affected` and `last_insert_rowid` but no rows.
31            fn execute<'e, 'q: 'e, E>(self, query: E) -> BoxFuture<'e, Result<DoQueryResult, Error>>
32            where
33                'c: 'e,
34                E: 'q + Execute<'q, Do>,
35            {
36                async move {
37                    let (sql, arguments) = take(query)?;
38                    js::run(&self.sql, sql.as_str(), arguments_of(arguments.as_ref()))
39                }
40                .boxed()
41            }
42
43            fn execute_many<'e, 'q: 'e, E>(
44                self,
45                query: E,
46            ) -> BoxStream<'e, Result<DoQueryResult, Error>>
47            where
48                'c: 'e,
49                E: 'q + Execute<'q, Do>,
50            {
51                stream::once(self.execute(query)).boxed()
52            }
53
54            /// Yields the rows only, never a `DoQueryResult`. Use
55            /// [`execute`](Executor::execute) for what a statement changed.
56            fn fetch_many<'e, 'q: 'e, E>(
57                self,
58                query: E,
59            ) -> BoxStream<'e, Result<Either<DoQueryResult, DoRow>, Error>>
60            where
61                'c: 'e,
62                E: 'q + Execute<'q, Do>,
63            {
64                async move {
65                    let (sql, arguments) = take(query)?;
66                    js::fetch(
67                        &self.sql,
68                        sql.as_str(),
69                        arguments_of(arguments.as_ref()),
70                        None,
71                    )
72                    .map(|(rows, _)| rows)
73                }
74                .map_ok(|rows| stream::iter(rows.into_iter().map(|row| Ok(Either::Right(row)))))
75                .try_flatten_stream()
76                .boxed()
77            }
78
79            fn fetch_optional<'e, 'q: 'e, E>(
80                self,
81                query: E,
82            ) -> BoxFuture<'e, Result<Option<DoRow>, Error>>
83            where
84                'c: 'e,
85                E: 'q + Execute<'q, Do>,
86            {
87                async move {
88                    let (sql, arguments) = take(query)?;
89                    let (rows, _) = js::fetch(
90                        &self.sql,
91                        sql.as_str(),
92                        arguments_of(arguments.as_ref()),
93                        Some(1),
94                    )?;
95                    Ok(rows.into_iter().next())
96                }
97                .boxed()
98            }
99
100            fn prepare_with<'e>(
101                self,
102                sql: SqlStr,
103                _parameters: &'e [DoTypeInfo],
104            ) -> BoxFuture<'e, Result<DoStatement, Error>>
105            where
106                'c: 'e,
107            {
108                future::ready(Ok(DoStatement { sql })).boxed()
109            }
110
111            /// Always fails: `sql.exec` cannot describe a statement without running
112            /// it. Only sqlx's `query!` macros need this, and they cannot target a
113            /// third-party driver anyway.
114            fn describe<'e>(self, _sql: SqlStr) -> BoxFuture<'e, Result<Describe<Do>, Error>>
115            where
116                'c: 'e,
117            {
118                future::ready(Err(unsupported("statements cannot be described"))).boxed()
119            }
120        }
121
122        // What sqlx code actually passes -- `&mut conn` -- running on the shared
123        // implementation above. `&'c mut` gives up its uniqueness to become `&'c`,
124        // which is all a query needs.
125        impl<'c> Executor<'c> for &'c mut $ty {
126            type Database = Do;
127
128            fn execute<'e, 'q: 'e, E>(self, query: E) -> BoxFuture<'e, Result<DoQueryResult, Error>>
129            where
130                'c: 'e,
131                E: 'q + Execute<'q, Do>,
132            {
133                (&*self).execute(query)
134            }
135
136            fn execute_many<'e, 'q: 'e, E>(
137                self,
138                query: E,
139            ) -> BoxStream<'e, Result<DoQueryResult, Error>>
140            where
141                'c: 'e,
142                E: 'q + Execute<'q, Do>,
143            {
144                (&*self).execute_many(query)
145            }
146
147            fn fetch_many<'e, 'q: 'e, E>(
148                self,
149                query: E,
150            ) -> BoxStream<'e, Result<Either<DoQueryResult, DoRow>, Error>>
151            where
152                'c: 'e,
153                E: 'q + Execute<'q, Do>,
154            {
155                (&*self).fetch_many(query)
156            }
157
158            fn fetch_optional<'e, 'q: 'e, E>(
159                self,
160                query: E,
161            ) -> BoxFuture<'e, Result<Option<DoRow>, Error>>
162            where
163                'c: 'e,
164                E: 'q + Execute<'q, Do>,
165            {
166                (&*self).fetch_optional(query)
167            }
168
169            fn prepare_with<'e>(
170                self,
171                sql: SqlStr,
172                parameters: &'e [DoTypeInfo],
173            ) -> BoxFuture<'e, Result<DoStatement, Error>>
174            where
175                'c: 'e,
176            {
177                (&*self).prepare_with(sql, parameters)
178            }
179
180            fn describe<'e>(self, sql: SqlStr) -> BoxFuture<'e, Result<Describe<Do>, Error>>
181            where
182                'c: 'e,
183            {
184                (&*self).describe(sql)
185            }
186        }
187    };
188}
189
190impl_executor!(DoConnection);
191impl_executor!(DoTransaction);
192
193/// `query`'s SQL and its arguments, bound.
194fn take<'q, E>(mut query: E) -> Result<(SqlStr, Option<DoArguments>), Error>
195where
196    E: Execute<'q, Do>,
197{
198    let arguments = query.take_arguments().map_err(Error::Encode)?;
199    Ok((query.sql(), arguments))
200}
201
202fn arguments_of(arguments: Option<&DoArguments>) -> &[crate::DoArgumentValue] {
203    arguments.map_or(&[][..], DoArguments::values)
204}