sqlx_rqlite/options/
connect.rs

1use crate::rqlite;
2use crate::connection::RqliteConnection;
3use crate::options::RqliteConnectOptions;
4
5use futures_core::future::BoxFuture;
6use log::LevelFilter;
7use sqlx_core::connection::ConnectOptions;
8use sqlx_core::error::Error;
9//use sqlx_core::executor::Executor;
10//use std::fmt::Write;
11use percent_encoding::percent_decode_str;
12use std::str::FromStr;
13use std::time::Duration;
14use url::Url;
15
16impl ConnectOptions for RqliteConnectOptions {
17    type Connection = RqliteConnection;
18    // borrowed from sqlx-mysql
19    fn from_url(url: &Url) -> Result<Self, Error> {
20        let mut options = rqlite::ConnectOptions::default();
21        if let Some(host) = url.host_str() {
22            options.host = host.into();
23        }
24
25        if let Some(port) = url.port() {
26            options.port = port;
27        }
28
29        let username = url.username();
30        if !username.is_empty() {
31            options.user = Some(
32                percent_decode_str(username)
33                    .decode_utf8()
34                    .map_err(Error::config)?
35                    .to_string(),
36            );
37        }
38
39        if let Some(password) = url.password() {
40            options.pass = Some(
41                percent_decode_str(password)
42                    .decode_utf8()
43                    .map_err(Error::config)?
44                    .to_string(),
45            );
46        }
47        /*
48        let path = url.path().trim_start_matches('/');
49        if !path.is_empty() {
50            options = options.database(path);
51        }
52        */
53        for (key, value) in url.query_pairs().into_iter() {
54            match &*key {
55              "ssl"=> {
56                if value == "yes" || value == "1" {
57                  options.scheme=rqlite::Scheme::HTTPS;
58                }
59              }
60              "ssl-insecure"=> {
61                if value == "yes" || value == "1" {
62                  options.scheme=rqlite::Scheme::HTTPS;
63                  options.accept_invalid_cert=true;
64                }
65              }
66              _=>{}
67            }
68        }
69        Ok(Self { inner: options })
70    }
71    fn to_url_lossy(&self) -> Url {
72        self.build_url()
73    }
74
75    fn connect(&self) -> BoxFuture<'_, Result<Self::Connection, Error>>
76    where
77        Self::Connection: Sized,
78    {
79        Box::pin(async move {
80            let conn = RqliteConnection::establish(self).await?;
81            /*
82                        // After the connection is established, we initialize by configuring a few
83                        // connection parameters
84
85                        // https://mariadb.com/kb/en/sql-mode/
86
87                        // PIPES_AS_CONCAT - Allows using the pipe character (ASCII 124) as string concatenation operator.
88                        //                   This means that "A" || "B" can be used in place of CONCAT("A", "B").
89
90                        // NO_ENGINE_SUBSTITUTION - If not set, if the available storage engine specified by a CREATE TABLE is
91                        //                          not available, a warning is given and the default storage
92                        //                          engine is used instead.
93
94                        // NO_ZERO_DATE - Don't allow '0000-00-00'. This is invalid in Rust.
95
96                        // NO_ZERO_IN_DATE - Don't allow 'YYYY-00-00'. This is invalid in Rust.
97
98                        // --
99
100                        // Setting the time zone allows us to assume that the output
101                        // from a TIMESTAMP field is UTC
102
103                        // --
104
105                        // https://mathiasbynens.be/notes/mysql-utf8mb4
106
107                        let mut sql_mode = Vec::new();
108                        if self.pipes_as_concat {
109                            sql_mode.push(r#"PIPES_AS_CONCAT"#);
110                        }
111                        if self.no_engine_subsitution {
112                            sql_mode.push(r#"NO_ENGINE_SUBSTITUTION"#);
113                        }
114
115                        let mut options = Vec::new();
116                        if !sql_mode.is_empty() {
117                            options.push(format!(
118                                r#"sql_mode=(SELECT CONCAT(@@sql_mode, ',{}'))"#,
119                                sql_mode.join(",")
120                            ));
121                        }
122                        if let Some(timezone) = &self.timezone {
123                            options.push(format!(r#"time_zone='{}'"#, timezone));
124                        }
125                        if self.set_names {
126                            options.push(format!(
127                                r#"NAMES {} COLLATE {}"#,
128                                conn.stream.charset.as_str(),
129                                conn.stream.collation.as_str()
130                            ))
131                        }
132
133                        if !options.is_empty() {
134                            conn.execute(&*format!(r#"SET {};"#, options.join(",")))
135                                .await?;
136                        }
137            */
138            Ok(conn)
139        })
140    }
141
142    fn log_statements(self, _level: LevelFilter) -> Self {
143        //self.log_settings.log_statements(level);
144        self
145    }
146
147    fn log_slow_statements(self, _level: LevelFilter, _duration: Duration) -> Self {
148        //self.log_settings.log_slow_statements(level, duration);
149        self
150    }
151}
152
153impl FromStr for RqliteConnectOptions {
154    type Err = Error;
155
156    fn from_str(s: &str) -> Result<Self, Error> {
157        let url: Url = s.parse().map_err(Error::config)?;
158        Self::from_url(&url)
159    }
160}