sqlx_core_oldapi/mysql/options/
parse.rs

1use crate::error::Error;
2use crate::mysql::MySqlConnectOptions;
3use percent_encoding::percent_decode_str;
4use std::str::FromStr;
5use url::Url;
6
7impl FromStr for MySqlConnectOptions {
8    type Err = Error;
9
10    fn from_str(s: &str) -> Result<Self, Error> {
11        let url: Url = s.parse().map_err(Error::config)?;
12        let mut options = Self::new();
13
14        if let Some(host) = url.host_str() {
15            options = options.host(host);
16        }
17
18        if let Some(port) = url.port() {
19            options = options.port(port);
20        }
21
22        let username = url.username();
23        if !username.is_empty() {
24            options = options.username(
25                &*percent_decode_str(username)
26                    .decode_utf8()
27                    .map_err(Error::config)?,
28            );
29        }
30
31        if let Some(password) = url.password() {
32            options = options.password(
33                &*percent_decode_str(password)
34                    .decode_utf8()
35                    .map_err(Error::config)?,
36            );
37        }
38
39        let path = url.path().trim_start_matches('/');
40        if !path.is_empty() {
41            options = options.database(path);
42        }
43
44        for (key, value) in url.query_pairs().into_iter() {
45            match &*key {
46                "sslmode" | "ssl-mode" => {
47                    options = options.ssl_mode(value.parse().map_err(Error::config)?);
48                }
49
50                "sslca" | "ssl-ca" => {
51                    options = options.ssl_ca(&*value);
52                }
53
54                "charset" => {
55                    options = options.charset(&*value);
56                }
57
58                "collation" => {
59                    options = options.collation(&*value);
60                }
61
62                "statement-cache-capacity" => {
63                    options =
64                        options.statement_cache_capacity(value.parse().map_err(Error::config)?);
65                }
66
67                "socket" => {
68                    options = options.socket(&*value);
69                }
70
71                "sslcert" | "ssl-cert" => options = options.ssl_client_cert(&*value),
72
73                "sslkey" | "ssl-key" => options = options.ssl_client_key(&*value),
74
75                _ => {}
76            }
77        }
78
79        Ok(options)
80    }
81}
82
83#[test]
84fn it_parses_username_with_at_sign_correctly() {
85    let url = "mysql://user@hostname:password@hostname:5432/database";
86    let opts = MySqlConnectOptions::from_str(url).unwrap();
87
88    assert_eq!("user@hostname", &opts.username);
89}
90
91#[test]
92fn it_parses_password_with_non_ascii_chars_correctly() {
93    let url = "mysql://username:p@ssw0rd@hostname:5432/database";
94    let opts = MySqlConnectOptions::from_str(url).unwrap();
95
96    assert_eq!(Some("p@ssw0rd".into()), opts.password);
97}