1
- use std:: pin:: Pin ;
2
-
3
1
use crate :: stmt_cache:: { PrepareCallback , StmtCache } ;
4
2
use crate :: {
5
3
AnsiTransactionManager , AsyncConnection , AsyncConnectionGatWorkaround , SimpleAsyncConnection ,
@@ -9,7 +7,9 @@ use diesel::mysql::{Mysql, MysqlType};
9
7
use diesel:: query_builder:: { bind_collector:: RawBytesBindCollector , QueryFragment , QueryId } ;
10
8
use diesel:: result:: { ConnectionError , ConnectionResult } ;
11
9
use diesel:: QueryResult ;
12
- use futures:: { Future , Stream , StreamExt , TryStreamExt } ;
10
+ use futures:: future:: BoxFuture ;
11
+ use futures:: stream:: BoxStream ;
12
+ use futures:: { Future , FutureExt , StreamExt , TryFutureExt , TryStreamExt } ;
13
13
use mysql_async:: prelude:: Queryable ;
14
14
use mysql_async:: { Opts , OptsBuilder , Statement } ;
15
15
@@ -35,8 +35,10 @@ impl SimpleAsyncConnection for AsyncMysqlConnection {
35
35
}
36
36
}
37
37
38
- impl < ' a > AsyncConnectionGatWorkaround < ' a , Mysql > for AsyncMysqlConnection {
39
- type Stream = Pin < Box < dyn Stream < Item = QueryResult < Self :: Row > > + Send + ' a > > ;
38
+ impl < ' conn , ' query > AsyncConnectionGatWorkaround < ' conn , ' query , Mysql > for AsyncMysqlConnection {
39
+ type ExecuteFuture = BoxFuture < ' conn , QueryResult < usize > > ;
40
+ type LoadFuture = BoxFuture < ' conn , QueryResult < Self :: Stream > > ;
41
+ type Stream = BoxStream < ' conn , QueryResult < Self :: Row > > ;
40
42
41
43
type Row = MysqlRow ;
42
44
}
@@ -50,13 +52,15 @@ impl AsyncConnection for AsyncMysqlConnection {
50
52
async fn establish ( database_url : & str ) -> diesel:: ConnectionResult < Self > {
51
53
let opts = Opts :: from_url ( database_url)
52
54
. map_err ( |e| diesel:: result:: ConnectionError :: InvalidConnectionUrl ( e. to_string ( ) ) ) ?;
53
- let builder = OptsBuilder :: from_opts ( opts) . init ( vec ! [
54
- "SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT'))" ,
55
- "SET time_zone = '+00:00';" ,
56
- "SET character_set_client = 'utf8mb4'" ,
57
- "SET character_set_connection = 'utf8mb4'" ,
58
- "SET character_set_results = 'utf8mb4'" ,
59
- ] ) ;
55
+ let builder = OptsBuilder :: from_opts ( opts)
56
+ . init ( vec ! [
57
+ "SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT'))" ,
58
+ "SET time_zone = '+00:00';" ,
59
+ "SET character_set_client = 'utf8mb4'" ,
60
+ "SET character_set_connection = 'utf8mb4'" ,
61
+ "SET character_set_results = 'utf8mb4'" ,
62
+ ] )
63
+ . stmt_cache_size ( 0 ) ; // We have our own cache
60
64
61
65
let conn = mysql_async:: Conn :: new ( builder) . await . map_err ( ErrorHelper ) ?;
62
66
@@ -68,15 +72,16 @@ impl AsyncConnection for AsyncMysqlConnection {
68
72
} )
69
73
}
70
74
71
- async fn load < ' a , T > (
72
- & ' a mut self ,
75
+ fn load < ' conn , ' query , T > (
76
+ & ' conn mut self ,
73
77
source : T ,
74
- ) -> diesel :: QueryResult < < Self as AsyncConnectionGatWorkaround < ' a , Self :: Backend > >:: Stream >
78
+ ) -> < Self as AsyncConnectionGatWorkaround < ' conn , ' query , Self :: Backend > >:: LoadFuture
75
79
where
76
80
T : diesel:: query_builder:: AsQuery + Send ,
77
81
T :: Query : diesel:: query_builder:: QueryFragment < Self :: Backend >
78
82
+ diesel:: query_builder:: QueryId
79
- + Send ,
83
+ + Send
84
+ + ' query ,
80
85
{
81
86
self . with_prepared_statement ( source. as_query ( ) , |conn, stmt, binds| async move {
82
87
let res = conn. exec_iter ( & * stmt, binds) . await . map_err ( ErrorHelper ) ?;
@@ -95,20 +100,23 @@ impl AsyncConnection for AsyncMysqlConnection {
95
100
96
101
Ok ( stream)
97
102
} )
98
- . await
103
+ . boxed ( )
99
104
}
100
105
101
- async fn execute_returning_count < T > ( & mut self , source : T ) -> diesel:: QueryResult < usize >
106
+ fn execute_returning_count < ' conn , ' query , T > (
107
+ & ' conn mut self ,
108
+ source : T ,
109
+ ) -> <Self as AsyncConnectionGatWorkaround < ' conn , ' query , Self :: Backend > >:: ExecuteFuture
102
110
where
103
111
T : diesel:: query_builder:: QueryFragment < Self :: Backend >
104
112
+ diesel:: query_builder:: QueryId
105
- + Send ,
113
+ + Send
114
+ + ' query ,
106
115
{
107
116
self . with_prepared_statement ( source, |conn, stmt, binds| async move {
108
117
conn. exec_drop ( & * stmt, binds) . await . map_err ( ErrorHelper ) ?;
109
118
Ok ( conn. affected_rows ( ) as usize )
110
119
} )
111
- . await
112
120
}
113
121
114
122
fn transaction_state ( & mut self ) -> & mut AnsiTransactionManager {
@@ -117,14 +125,15 @@ impl AsyncConnection for AsyncMysqlConnection {
117
125
}
118
126
119
127
#[ async_trait:: async_trait]
120
- impl PrepareCallback < Statement , MysqlType > for mysql_async:: Conn {
128
+ impl PrepareCallback < Statement , MysqlType > for & ' _ mut mysql_async:: Conn {
121
129
async fn prepare (
122
- & mut self ,
130
+ self ,
123
131
sql : & str ,
124
132
_metadata : & [ MysqlType ] ,
125
133
_is_for_cache : diesel:: connection:: statement_cache:: PrepareForCache ,
126
- ) -> QueryResult < Statement > {
127
- Ok ( self . prep ( sql) . await . map_err ( ErrorHelper ) ?)
134
+ ) -> QueryResult < ( Statement , Self ) > {
135
+ let s = self . prep ( sql) . await . map_err ( ErrorHelper ) ?;
136
+ Ok ( ( s, self ) )
128
137
}
129
138
}
130
139
@@ -155,17 +164,22 @@ impl AsyncMysqlConnection {
155
164
Ok ( conn)
156
165
}
157
166
158
- async fn with_prepared_statement < ' a , T , F , R > (
159
- & ' a mut self ,
167
+ fn with_prepared_statement < ' conn , T , F , R > (
168
+ & ' conn mut self ,
160
169
query : T ,
161
- callback : impl FnOnce ( & ' a mut mysql_async:: Conn , & ' a Statement , ToSqlHelper ) -> F ,
162
- ) -> QueryResult < R >
170
+ callback : impl ( FnOnce ( & ' conn mut mysql_async:: Conn , & ' conn Statement , ToSqlHelper ) -> F )
171
+ + Send
172
+ + ' conn ,
173
+ ) -> BoxFuture < ' conn , QueryResult < R > >
163
174
where
175
+ R : Send + ' conn ,
164
176
T : QueryFragment < Mysql > + QueryId + Send ,
165
- F : Future < Output = QueryResult < R > > ,
177
+ F : Future < Output = QueryResult < R > > + Send ,
166
178
{
167
179
let mut bind_collector = RawBytesBindCollector :: < Mysql > :: new ( ) ;
168
- query. collect_binds ( & mut bind_collector, & mut ( ) , & Mysql ) ?;
180
+ if let Err ( e) = query. collect_binds ( & mut bind_collector, & mut ( ) , & Mysql ) {
181
+ return futures:: future:: ready ( Err ( e) ) . boxed ( ) ;
182
+ }
169
183
170
184
let binds = bind_collector. binds ;
171
185
let metadata = bind_collector. metadata ;
@@ -177,24 +191,19 @@ impl AsyncMysqlConnection {
177
191
..
178
192
} = self ;
179
193
180
- let conn = & mut * conn;
194
+ let stmt = stmt_cache . cached_prepared_statement ( query , & metadata , conn, & Mysql ) ;
181
195
182
- let stmt = {
183
- let stmt = stmt_cache
184
- . cached_prepared_statement ( query, & metadata, conn, & Mysql )
185
- . await ?;
186
- stmt
187
- } ;
188
-
189
- let stmt = match stmt {
190
- MaybeCached :: CannotCache ( stmt) => {
191
- * last_stmt = Some ( stmt) ;
192
- last_stmt. as_ref ( ) . unwrap ( )
193
- }
194
- MaybeCached :: Cached ( s) => s,
195
- _ => unreachable ! ( "We've opted into breaking diesel changes and want to know if things break because someone added a new variant here" )
196
- } ;
196
+ stmt. and_then ( |( stmt, conn) |async move {
197
197
198
- callback ( & mut self . conn , stmt, ToSqlHelper { metadata, binds } ) . await
198
+ let stmt = match stmt {
199
+ MaybeCached :: CannotCache ( stmt) => {
200
+ * last_stmt = Some ( stmt) ;
201
+ last_stmt. as_ref ( ) . unwrap ( )
202
+ }
203
+ MaybeCached :: Cached ( s) => s,
204
+ _ => unreachable ! ( "We've opted into breaking diesel changes and want to know if things break because someone added a new variant here" )
205
+ } ;
206
+ callback ( conn, stmt, ToSqlHelper { metadata, binds} ) . await
207
+ } ) . boxed ( )
199
208
}
200
209
}
0 commit comments