sqlx_migrate/
context.rs

1use sha2::{Digest, Sha256};
2use state::TypeMap;
3use std::{any::Any, borrow::BorrowMut, sync::Arc};
4
5use sqlx::{Database, Executor};
6
7pub struct MigrationContext<Db>
8where
9    Db: Database,
10{
11    pub(crate) hash_only: bool,
12    pub(crate) hasher: Sha256,
13    pub(crate) conn: Db::Connection,
14    pub(crate) ext: Arc<TypeMap![Send + Sync]>,
15}
16
17impl<Db: std::fmt::Debug> std::fmt::Debug for MigrationContext<Db>
18where
19    Db: Database,
20{
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        f.debug_struct("MigrationContext")
23            .field("hash_only", &self.hash_only)
24            .field("hasher", &self.hasher)
25            .field("ext", &self.ext)
26            .finish_non_exhaustive()
27    }
28}
29
30impl<Db> MigrationContext<Db>
31where
32    Db: Database,
33{
34    /// Return an executor that can execute queries.
35    ///
36    /// Currently this just re-borrows self.
37    pub fn tx(&mut self) -> &mut Self {
38        self
39    }
40
41    /// Get an extension.
42    #[must_use]
43    pub fn get<T: Any>(&self) -> Option<&T> {
44        self.ext.try_get()
45    }
46}
47
48// Implementing this in a generic way confuses the hell out of rustc,
49// so instead this is copy/pasted for all supported backends.
50#[cfg(feature = "postgres")]
51impl<'c> Executor<'c> for &'c mut MigrationContext<sqlx::Postgres> {
52    type Database = sqlx::Postgres;
53
54    fn fetch_many<'e, 'q: 'e, E: 'q>(
55        self,
56        query: E,
57    ) -> futures_core::stream::BoxStream<
58        'e,
59        Result<
60            itertools::Either<
61                <Self::Database as Database>::QueryResult,
62                <Self::Database as Database>::Row,
63            >,
64            sqlx::Error,
65        >,
66    >
67    where
68        'c: 'e,
69        E: sqlx::Execute<'q, Self::Database>,
70    {
71        self.hasher.update(query.sql());
72
73        if self.hash_only {
74            return self.conn.borrow_mut().fetch_many("");
75        }
76
77        self.conn.borrow_mut().fetch_many(query)
78    }
79
80    fn fetch_optional<'e, 'q: 'e, E: 'q>(
81        self,
82        query: E,
83    ) -> futures_core::future::BoxFuture<
84        'e,
85        Result<Option<<Self::Database as Database>::Row>, sqlx::Error>,
86    >
87    where
88        'c: 'e,
89        E: sqlx::Execute<'q, Self::Database>,
90    {
91        self.hasher.update(query.sql());
92
93        if self.hash_only {
94            return Box::pin(async move { Ok(None) });
95        }
96
97        self.conn.borrow_mut().fetch_optional(query)
98    }
99
100    fn prepare_with<'e, 'q: 'e>(
101        self,
102        sql: &'q str,
103        parameters: &'e [<Self::Database as Database>::TypeInfo],
104    ) -> futures_core::future::BoxFuture<
105        'e,
106        Result<<Self::Database as sqlx::database::HasStatement<'q>>::Statement, sqlx::Error>,
107    >
108    where
109        'c: 'e,
110    {
111        self.hasher.update(sql);
112        self.conn.borrow_mut().prepare_with(sql, parameters)
113    }
114
115    fn describe<'e, 'q: 'e>(
116        self,
117        sql: &'q str,
118    ) -> futures_core::future::BoxFuture<'e, Result<sqlx::Describe<Self::Database>, sqlx::Error>>
119    where
120        'c: 'e,
121    {
122        self.hasher.update(sql);
123        self.conn.borrow_mut().describe(sql)
124    }
125
126    fn execute<'e, 'q: 'e, E: 'q>(
127        self,
128        query: E,
129    ) -> futures_core::future::BoxFuture<
130        'e,
131        Result<<Self::Database as Database>::QueryResult, sqlx::Error>,
132    >
133    where
134        'c: 'e,
135        E: sqlx::Execute<'q, Self::Database>,
136    {
137        self.hasher.update(query.sql());
138
139        if self.hash_only {
140            return self.conn.borrow_mut().execute("");
141        }
142
143        self.conn.borrow_mut().execute(query)
144    }
145
146    fn execute_many<'e, 'q: 'e, E: 'q>(
147        self,
148        query: E,
149    ) -> futures_core::stream::BoxStream<
150        'e,
151        Result<<Self::Database as Database>::QueryResult, sqlx::Error>,
152    >
153    where
154        'c: 'e,
155        E: sqlx::Execute<'q, Self::Database>,
156    {
157        self.hasher.update(query.sql());
158
159        if self.hash_only {
160            return self.conn.borrow_mut().execute_many("");
161        }
162
163        self.conn.borrow_mut().execute_many(query)
164    }
165
166    fn fetch<'e, 'q: 'e, E: 'q>(
167        self,
168        query: E,
169    ) -> futures_core::stream::BoxStream<'e, Result<<Self::Database as Database>::Row, sqlx::Error>>
170    where
171        'c: 'e,
172        E: sqlx::Execute<'q, Self::Database>,
173    {
174        self.hasher.update(query.sql());
175
176        if self.hash_only {
177            return self.conn.borrow_mut().fetch("");
178        }
179
180        self.conn.borrow_mut().fetch(query)
181    }
182
183    fn fetch_all<'e, 'q: 'e, E: 'q>(
184        self,
185        query: E,
186    ) -> futures_core::future::BoxFuture<
187        'e,
188        Result<Vec<<Self::Database as Database>::Row>, sqlx::Error>,
189    >
190    where
191        'c: 'e,
192        E: sqlx::Execute<'q, Self::Database>,
193    {
194        self.hasher.update(query.sql());
195
196        if self.hash_only {
197            return self.conn.borrow_mut().fetch_all("");
198        }
199
200        self.conn.borrow_mut().fetch_all(query)
201    }
202
203    fn fetch_one<'e, 'q: 'e, E: 'q>(
204        self,
205        query: E,
206    ) -> futures_core::future::BoxFuture<'e, Result<<Self::Database as Database>::Row, sqlx::Error>>
207    where
208        'c: 'e,
209        E: sqlx::Execute<'q, Self::Database>,
210    {
211        self.hasher.update(query.sql());
212
213        if self.hash_only {
214            return self.conn.borrow_mut().fetch_one("");
215        }
216
217        self.conn.borrow_mut().fetch_one(query)
218    }
219
220    fn prepare<'e, 'q: 'e>(
221        self,
222        query: &'q str,
223    ) -> futures_core::future::BoxFuture<
224        'e,
225        Result<<Self::Database as sqlx::database::HasStatement<'q>>::Statement, sqlx::Error>,
226    >
227    where
228        'c: 'e,
229    {
230        self.hasher.update(query);
231        self.conn.borrow_mut().prepare(query)
232    }
233}
234
235// Implementing this in a generic way confuses the hell out of rustc,
236// so instead this is copy/pasted for all supported backends.
237#[cfg(feature = "sqlite")]
238impl<'c> Executor<'c> for &'c mut MigrationContext<sqlx::Sqlite> {
239    type Database = sqlx::Sqlite;
240
241    fn fetch_many<'e, 'q: 'e, E: 'q>(
242        self,
243        query: E,
244    ) -> futures_core::stream::BoxStream<
245        'e,
246        Result<
247            itertools::Either<
248                <Self::Database as Database>::QueryResult,
249                <Self::Database as Database>::Row,
250            >,
251            sqlx::Error,
252        >,
253    >
254    where
255        'c: 'e,
256        E: sqlx::Execute<'q, Self::Database>,
257    {
258        self.hasher.update(query.sql());
259
260        if self.hash_only {
261            return self.conn.borrow_mut().fetch_many("");
262        }
263
264        self.conn.borrow_mut().fetch_many(query)
265    }
266
267    fn fetch_optional<'e, 'q: 'e, E: 'q>(
268        self,
269        query: E,
270    ) -> futures_core::future::BoxFuture<
271        'e,
272        Result<Option<<Self::Database as Database>::Row>, sqlx::Error>,
273    >
274    where
275        'c: 'e,
276        E: sqlx::Execute<'q, Self::Database>,
277    {
278        self.hasher.update(query.sql());
279
280        if self.hash_only {
281            return Box::pin(async move { Ok(None) });
282        }
283
284        self.conn.borrow_mut().fetch_optional(query)
285    }
286
287    fn prepare_with<'e, 'q: 'e>(
288        self,
289        sql: &'q str,
290        parameters: &'e [<Self::Database as Database>::TypeInfo],
291    ) -> futures_core::future::BoxFuture<
292        'e,
293        Result<<Self::Database as sqlx::database::HasStatement<'q>>::Statement, sqlx::Error>,
294    >
295    where
296        'c: 'e,
297    {
298        self.hasher.update(sql);
299        self.conn.borrow_mut().prepare_with(sql, parameters)
300    }
301
302    fn describe<'e, 'q: 'e>(
303        self,
304        sql: &'q str,
305    ) -> futures_core::future::BoxFuture<'e, Result<sqlx::Describe<Self::Database>, sqlx::Error>>
306    where
307        'c: 'e,
308    {
309        self.hasher.update(sql);
310        self.conn.borrow_mut().describe(sql)
311    }
312
313    fn execute<'e, 'q: 'e, E: 'q>(
314        self,
315        query: E,
316    ) -> futures_core::future::BoxFuture<
317        'e,
318        Result<<Self::Database as Database>::QueryResult, sqlx::Error>,
319    >
320    where
321        'c: 'e,
322        E: sqlx::Execute<'q, Self::Database>,
323    {
324        self.hasher.update(query.sql());
325
326        if self.hash_only {
327            return self.conn.borrow_mut().execute("");
328        }
329
330        self.conn.borrow_mut().execute(query)
331    }
332
333    fn execute_many<'e, 'q: 'e, E: 'q>(
334        self,
335        query: E,
336    ) -> futures_core::stream::BoxStream<
337        'e,
338        Result<<Self::Database as Database>::QueryResult, sqlx::Error>,
339    >
340    where
341        'c: 'e,
342        E: sqlx::Execute<'q, Self::Database>,
343    {
344        self.hasher.update(query.sql());
345
346        if self.hash_only {
347            return self.conn.borrow_mut().execute_many("");
348        }
349
350        self.conn.borrow_mut().execute_many(query)
351    }
352
353    fn fetch<'e, 'q: 'e, E: 'q>(
354        self,
355        query: E,
356    ) -> futures_core::stream::BoxStream<'e, Result<<Self::Database as Database>::Row, sqlx::Error>>
357    where
358        'c: 'e,
359        E: sqlx::Execute<'q, Self::Database>,
360    {
361        self.hasher.update(query.sql());
362
363        if self.hash_only {
364            return self.conn.borrow_mut().fetch("");
365        }
366
367        self.conn.borrow_mut().fetch(query)
368    }
369
370    fn fetch_all<'e, 'q: 'e, E: 'q>(
371        self,
372        query: E,
373    ) -> futures_core::future::BoxFuture<
374        'e,
375        Result<Vec<<Self::Database as Database>::Row>, sqlx::Error>,
376    >
377    where
378        'c: 'e,
379        E: sqlx::Execute<'q, Self::Database>,
380    {
381        self.hasher.update(query.sql());
382
383        if self.hash_only {
384            return self.conn.borrow_mut().fetch_all("");
385        }
386
387        self.conn.borrow_mut().fetch_all(query)
388    }
389
390    fn fetch_one<'e, 'q: 'e, E: 'q>(
391        self,
392        query: E,
393    ) -> futures_core::future::BoxFuture<'e, Result<<Self::Database as Database>::Row, sqlx::Error>>
394    where
395        'c: 'e,
396        E: sqlx::Execute<'q, Self::Database>,
397    {
398        self.hasher.update(query.sql());
399
400        if self.hash_only {
401            return self.conn.borrow_mut().fetch_one("");
402        }
403
404        self.conn.borrow_mut().fetch_one(query)
405    }
406
407    fn prepare<'e, 'q: 'e>(
408        self,
409        query: &'q str,
410    ) -> futures_core::future::BoxFuture<
411        'e,
412        Result<<Self::Database as sqlx::database::HasStatement<'q>>::Statement, sqlx::Error>,
413    >
414    where
415        'c: 'e,
416    {
417        self.hasher.update(query);
418        self.conn.borrow_mut().prepare(query)
419    }
420}