1
+ #[ cfg( feature = "sqlx-any" ) ]
2
+ use sqlx:: any:: AnyKind ;
3
+ #[ cfg( feature = "sqlx-mysql" ) ]
4
+ use sqlx:: mysql:: MySqlConnectOptions ;
5
+ #[ cfg( feature = "sqlx-postgres" ) ]
6
+ use sqlx:: postgres:: PgConnectOptions ;
7
+ #[ cfg( feature = "sqlx-sqlite" ) ]
8
+ use sqlx:: sqlite:: SqliteConnectOptions ;
9
+ use std:: fmt:: Debug ;
1
10
use std:: time:: Duration ;
2
11
3
12
mod connection;
@@ -23,11 +32,55 @@ use crate::DbErr;
23
32
#[ derive( Debug , Default ) ]
24
33
pub struct Database ;
25
34
35
+ /// Supported database kinds of [sqlx::ConnectOptions]'.
36
+ #[ derive( Debug , Clone ) ]
37
+ pub enum SqlxConnectOptions {
38
+ #[ cfg( feature = "sqlx-mysql" ) ]
39
+ MySql ( MySqlConnectOptions ) ,
40
+ #[ cfg( feature = "sqlx-postgres" ) ]
41
+ Postgres ( PgConnectOptions ) ,
42
+ #[ cfg( feature = "sqlx-sqlite" ) ]
43
+ Sqlite ( SqliteConnectOptions ) ,
44
+ #[ cfg( feature = "mock" ) ]
45
+ Mock ( DbBackend ) ,
46
+ }
47
+
48
+ impl SqlxConnectOptions {
49
+ /// The database backend type
50
+ pub fn get_db_backend_type ( & self ) -> DbBackend {
51
+ match self {
52
+ #[ cfg( feature = "sqlx-mysql" ) ]
53
+ SqlxConnectOptions :: MySql ( _) => DbBackend :: MySql ,
54
+ #[ cfg( feature = "sqlx-postgres" ) ]
55
+ SqlxConnectOptions :: Postgres ( _) => DbBackend :: Postgres ,
56
+ #[ cfg( feature = "sqlx-sqlite" ) ]
57
+ SqlxConnectOptions :: Sqlite ( _) => DbBackend :: Sqlite ,
58
+ #[ cfg( feature = "mock" ) ]
59
+ SqlxConnectOptions :: Mock ( db_backend) => db_backend. clone ( ) ,
60
+ }
61
+ }
62
+
63
+ #[ cfg( feature = "mock" ) ]
64
+ pub fn mock ( db_backend : DbBackend ) -> SqlxConnectOptions {
65
+ Self :: Mock ( db_backend)
66
+ }
67
+
68
+ #[ cfg( feature = "mock" ) ]
69
+ pub fn is_mock ( & self ) -> bool {
70
+ match self {
71
+ SqlxConnectOptions :: Mock ( _) => true ,
72
+ _ => false ,
73
+ }
74
+ }
75
+ }
76
+
26
77
/// Defines the configuration options of a database
27
78
#[ derive( Debug ) ]
28
79
pub struct ConnectOptions {
29
- /// The URI of the database
30
- pub ( crate ) url : String ,
80
+ /// The database sqlx::ConnectOptions used to connect to the database.
81
+ pub ( crate ) connect_options : SqlxConnectOptions ,
82
+ /// The URI of the database, if this struct was created from an URI string, otherwise None
83
+ pub ( crate ) url : Option < String > ,
31
84
/// Maximum number of connections for a pool
32
85
pub ( crate ) max_connections : Option < u32 > ,
33
86
/// Minimum number of connections for a pool
@@ -44,58 +97,165 @@ pub struct ConnectOptions {
44
97
impl Database {
45
98
/// Method to create a [DatabaseConnection] on a database
46
99
#[ instrument( level = "trace" , skip( opt) ) ]
47
- pub async fn connect < C > ( opt : C ) -> Result < DatabaseConnection , DbErr >
100
+ pub async fn connect < C , E > ( opt : C ) -> Result < DatabaseConnection , DbErr >
48
101
where
49
- C : Into < ConnectOptions > ,
102
+ C : TryInto < ConnectOptions , Error = E > + Debug ,
103
+ E : std:: error:: Error ,
50
104
{
51
- let opt: ConnectOptions = opt. into ( ) ;
105
+ let describe = format ! ( "{:?}" , opt) ;
106
+ let opt: ConnectOptions = opt
107
+ . try_into ( )
108
+ . map_err ( |e| DbErr :: Conn ( format ! ( "Couldn't parse connection options {}" , e) ) ) ?;
52
109
53
- #[ cfg( feature = "sqlx-mysql" ) ]
54
- if DbBackend :: MySql . is_prefix_of ( & opt. url ) {
55
- return crate :: SqlxMySqlConnector :: connect ( opt) . await ;
56
- }
57
- #[ cfg( feature = "sqlx-postgres" ) ]
58
- if DbBackend :: Postgres . is_prefix_of ( & opt. url ) {
59
- return crate :: SqlxPostgresConnector :: connect ( opt) . await ;
60
- }
61
- #[ cfg( feature = "sqlx-sqlite" ) ]
62
- if DbBackend :: Sqlite . is_prefix_of ( & opt. url ) {
63
- return crate :: SqlxSqliteConnector :: connect ( opt) . await ;
64
- }
65
110
#[ cfg( feature = "mock" ) ]
66
- if crate :: MockDatabaseConnector :: accepts ( & opt. url ) {
67
- return crate :: MockDatabaseConnector :: connect ( & opt. url ) . await ;
111
+ if opt. connect_options . is_mock ( ) {
112
+ return crate :: MockDatabaseConnector :: connect ( opt) . await ;
113
+ }
114
+
115
+ let backend = opt. connect_options . get_db_backend_type ( ) ;
116
+
117
+ match backend {
118
+ #[ cfg( feature = "sqlx-mysql" ) ]
119
+ DbBackend :: MySql => crate :: SqlxMySqlConnector :: connect ( opt) . await ,
120
+ #[ cfg( feature = "sqlx-postgres" ) ]
121
+ DbBackend :: Postgres => crate :: SqlxPostgresConnector :: connect ( opt) . await ,
122
+ #[ cfg( feature = "sqlx-sqlite" ) ]
123
+ DbBackend :: Sqlite => crate :: SqlxSqliteConnector :: connect ( opt) . await ,
124
+ _ => {
125
+ return Err ( DbErr :: Conn ( format ! (
126
+ "The connection option {} has no supporting driver." ,
127
+ describe
128
+ ) ) ) ;
129
+ }
68
130
}
69
- Err ( DbErr :: Conn ( format ! (
70
- "The connection string '{}' has no supporting driver." ,
71
- opt. url
72
- ) ) )
73
131
}
74
132
}
75
133
76
- impl From < & str > for ConnectOptions {
77
- fn from ( string : & str ) -> ConnectOptions {
134
+ impl TryFrom < & str > for ConnectOptions {
135
+ type Error = DbErr ;
136
+
137
+ fn try_from ( string : & str ) -> Result < Self , Self :: Error > {
78
138
ConnectOptions :: from_str ( string)
79
139
}
80
140
}
81
141
82
- impl From < & String > for ConnectOptions {
83
- fn from ( string : & String ) -> ConnectOptions {
142
+ impl TryFrom < & String > for ConnectOptions {
143
+ type Error = DbErr ;
144
+
145
+ fn try_from ( string : & String ) -> Result < Self , Self :: Error > {
84
146
ConnectOptions :: from_str ( string. as_str ( ) )
85
147
}
86
148
}
87
149
88
- impl From < String > for ConnectOptions {
89
- fn from ( string : String ) -> ConnectOptions {
90
- ConnectOptions :: new ( string)
150
+ impl TryFrom < String > for ConnectOptions {
151
+ type Error = DbErr ;
152
+
153
+ fn try_from ( string : String ) -> Result < Self , Self :: Error > {
154
+ ConnectOptions :: new_from_url ( string)
155
+ }
156
+ }
157
+
158
+ #[ cfg( feature = "sqlx-mysql" ) ]
159
+ impl TryFrom < MySqlConnectOptions > for ConnectOptions {
160
+ type Error = DbErr ;
161
+
162
+ fn try_from ( connect_options : MySqlConnectOptions ) -> Result < Self , Self :: Error > {
163
+ Ok ( ConnectOptions :: new ( SqlxConnectOptions :: MySql (
164
+ connect_options,
165
+ ) ) )
166
+ }
167
+ }
168
+
169
+ #[ cfg( feature = "sqlx-postgres" ) ]
170
+ impl TryFrom < PgConnectOptions > for ConnectOptions {
171
+ type Error = DbErr ;
172
+
173
+ fn try_from ( connect_options : PgConnectOptions ) -> Result < Self , Self :: Error > {
174
+ Ok ( ConnectOptions :: new ( SqlxConnectOptions :: Postgres (
175
+ connect_options,
176
+ ) ) )
177
+ }
178
+ }
179
+
180
+ #[ cfg( feature = "sqlx-sqlite" ) ]
181
+ impl TryFrom < SqliteConnectOptions > for ConnectOptions {
182
+ type Error = DbErr ;
183
+
184
+ fn try_from ( connect_options : SqliteConnectOptions ) -> Result < Self , Self :: Error > {
185
+ Ok ( ConnectOptions :: new ( SqlxConnectOptions :: Sqlite (
186
+ connect_options,
187
+ ) ) )
188
+ }
189
+ }
190
+
191
+ #[ cfg( feature = "sqlx-any" ) ]
192
+ impl TryFrom < sqlx:: any:: AnyConnectOptions > for ConnectOptions {
193
+ type Error = DbErr ;
194
+
195
+ fn try_from ( connect_options : sqlx:: any:: AnyConnectOptions ) -> Result < Self , Self :: Error > {
196
+ Ok ( ConnectOptions :: new ( connect_options. try_into ( ) ?) )
197
+ }
198
+ }
199
+
200
+ #[ cfg( feature = "sqlx-mysql" ) ]
201
+ impl TryFrom < MySqlConnectOptions > for SqlxConnectOptions {
202
+ type Error = DbErr ;
203
+
204
+ fn try_from ( connect_options : MySqlConnectOptions ) -> Result < Self , Self :: Error > {
205
+ Ok ( SqlxConnectOptions :: MySql ( connect_options) )
206
+ }
207
+ }
208
+
209
+ #[ cfg( feature = "sqlx-postgres" ) ]
210
+ impl TryFrom < PgConnectOptions > for SqlxConnectOptions {
211
+ type Error = DbErr ;
212
+
213
+ fn try_from ( connect_options : PgConnectOptions ) -> Result < Self , Self :: Error > {
214
+ Ok ( SqlxConnectOptions :: Postgres ( connect_options) )
215
+ }
216
+ }
217
+
218
+ #[ cfg( feature = "sqlx-sqlite" ) ]
219
+ impl TryFrom < SqliteConnectOptions > for SqlxConnectOptions {
220
+ type Error = DbErr ;
221
+
222
+ fn try_from ( connect_options : SqliteConnectOptions ) -> Result < Self , Self :: Error > {
223
+ Ok ( SqlxConnectOptions :: Sqlite ( connect_options) )
224
+ }
225
+ }
226
+
227
+ #[ cfg( feature = "sqlx-any" ) ]
228
+ impl TryFrom < sqlx:: any:: AnyConnectOptions > for SqlxConnectOptions {
229
+ type Error = DbErr ;
230
+
231
+ fn try_from ( connect_options : sqlx:: any:: AnyConnectOptions ) -> Result < Self , Self :: Error > {
232
+ match connect_options. kind ( ) {
233
+ #[ cfg( feature = "sqlx-postgres" ) ]
234
+ AnyKind :: Postgres => Ok ( SqlxConnectOptions :: Postgres (
235
+ connect_options. as_postgres_cloned ( ) . unwrap ( ) ,
236
+ ) ) ,
237
+ #[ cfg( feature = "sqlx-mysql" ) ]
238
+ AnyKind :: MySql => Ok ( SqlxConnectOptions :: MySql (
239
+ connect_options. as_mysql_cloned ( ) . unwrap ( ) ,
240
+ ) ) ,
241
+ #[ cfg( feature = "sqlx-sqlite" ) ]
242
+ AnyKind :: Sqlite => Ok ( SqlxConnectOptions :: Sqlite (
243
+ connect_options. as_sqlite_cloned ( ) . unwrap ( ) ,
244
+ ) ) ,
245
+ _ => Err ( DbErr :: Conn ( format ! (
246
+ "Sea orm doesn't support sqlx database kind: {:?}!" ,
247
+ connect_options. kind( )
248
+ ) ) ) ,
249
+ }
91
250
}
92
251
}
93
252
94
253
impl ConnectOptions {
95
- /// Create new [ConnectOptions] for a [Database] by passing in a URI string
96
- pub fn new ( url : String ) -> Self {
254
+ /// Create new [ConnectOptions] for a [Database] by passing in a [sqlx::ConnectOptions]
255
+ pub fn new ( connect_options : SqlxConnectOptions ) -> Self {
97
256
Self {
98
- url,
257
+ connect_options,
258
+ url : None ,
99
259
max_connections : None ,
100
260
min_connections : None ,
101
261
connect_timeout : None ,
@@ -104,8 +264,64 @@ impl ConnectOptions {
104
264
}
105
265
}
106
266
107
- fn from_str ( url : & str ) -> Self {
108
- Self :: new ( url. to_owned ( ) )
267
+ /// Create new [ConnectOptions] for a [Database] by passing in a URI string
268
+ pub fn new_from_url ( url : String ) -> Result < Self , DbErr > {
269
+ Ok ( Self {
270
+ connect_options : Self :: url_to_sqlx_connect_options ( url. clone ( ) ) ?,
271
+ url : Some ( url) ,
272
+ max_connections : None ,
273
+ min_connections : None ,
274
+ connect_timeout : None ,
275
+ idle_timeout : None ,
276
+ sqlx_logging : true ,
277
+ } )
278
+ }
279
+
280
+ fn url_to_sqlx_connect_options ( url : String ) -> Result < SqlxConnectOptions , DbErr > {
281
+ #[ cfg( feature = "sqlx-mysql" ) ]
282
+ if DbBackend :: MySql . is_prefix_of ( & url) {
283
+ return Ok ( url
284
+ . parse :: < MySqlConnectOptions > ( )
285
+ . map_err ( |e| DbErr :: Conn ( e. to_string ( ) ) ) ?
286
+ . try_into ( ) ?) ;
287
+ }
288
+ #[ cfg( feature = "sqlx-postgres" ) ]
289
+ if DbBackend :: Postgres . is_prefix_of ( & url) {
290
+ return Ok ( url
291
+ . parse :: < PgConnectOptions > ( )
292
+ . map_err ( |e| DbErr :: Conn ( e. to_string ( ) ) ) ?
293
+ . try_into ( ) ?) ;
294
+ }
295
+ #[ cfg( feature = "sqlx-sqlite" ) ]
296
+ if DbBackend :: Sqlite . is_prefix_of ( & url) {
297
+ return Ok ( url
298
+ . parse :: < SqliteConnectOptions > ( )
299
+ . map_err ( |e| DbErr :: Conn ( e. to_string ( ) ) ) ?
300
+ . try_into ( ) ?) ;
301
+ }
302
+ #[ cfg( feature = "mock" ) ]
303
+ if crate :: MockDatabaseConnector :: accepts ( & url) {
304
+ if DbBackend :: MySql . is_prefix_of ( & url) {
305
+ return Ok ( SqlxConnectOptions :: Mock ( DbBackend :: MySql ) ) ;
306
+ }
307
+ #[ cfg( feature = "sqlx-postgres" ) ]
308
+ if DbBackend :: Postgres . is_prefix_of ( & url) {
309
+ return Ok ( SqlxConnectOptions :: Mock ( DbBackend :: Postgres ) ) ;
310
+ }
311
+ #[ cfg( feature = "sqlx-sqlite" ) ]
312
+ if DbBackend :: Sqlite . is_prefix_of ( & url) {
313
+ return Ok ( SqlxConnectOptions :: Mock ( DbBackend :: Sqlite ) ) ;
314
+ }
315
+ return Ok ( SqlxConnectOptions :: Mock ( DbBackend :: Postgres ) ) ;
316
+ }
317
+ Err ( DbErr :: Conn ( format ! (
318
+ "The connection string '{}' has no supporting driver." ,
319
+ url
320
+ ) ) )
321
+ }
322
+
323
+ fn from_str ( url : & str ) -> Result < Self , DbErr > {
324
+ Self :: new_from_url ( url. to_owned ( ) )
109
325
}
110
326
111
327
#[ cfg( feature = "sqlx-dep" ) ]
@@ -130,11 +346,19 @@ impl ConnectOptions {
130
346
opt
131
347
}
132
348
133
- /// Get the database URL of the pool
134
- pub fn get_url ( & self ) -> & str {
349
+ /// Get the database URL of the pool. This is only present if the pool was created from an URL.
350
+ /// If it was created from some sqlx::ConnectOptions then this method returns None.
351
+ ///
352
+ /// To get the actual ConnectOptions used to connect to the database see: [Self::get_connect_options].
353
+ pub fn get_url ( & self ) -> & Option < String > {
135
354
& self . url
136
355
}
137
356
357
+ /// Get the ConnectOptions used to connect to the database
358
+ pub fn get_connect_options ( & self ) -> & SqlxConnectOptions {
359
+ & self . connect_options
360
+ }
361
+
138
362
/// Set the maximum number of connections of the pool
139
363
pub fn max_connections ( & mut self , value : u32 ) -> & mut Self {
140
364
self . max_connections = Some ( value) ;
0 commit comments