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 pub fn tx(&mut self) -> &mut Self {
38 self
39 }
40
41 #[must_use]
43 pub fn get<T: Any>(&self) -> Option<&T> {
44 self.ext.try_get()
45 }
46}
47
48#[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#[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}