rbdc_mysql/options/
parse.rs

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