sqlx_firebird/options/
parse.rs1use std::str::FromStr;
7
8use rsfbclient::charset::Charset;
9use rsfbclient::{Dialect, FbError};
10use sqlx_core::error::Error;
11use sqlx_core::percent_encoding::percent_decode_str;
12use sqlx_core::Url;
13
14use super::FbConnectOptions;
15
16impl FbConnectOptions {
17 pub(crate) fn parse_from_url(url: &Url) -> Result<Self, Error> {
18 let settings = parse(url).map_err(Error::config)?;
19
20 let mut options = FbConnectOptions::new();
21
22 if let Some(user) = settings.user {
23 options = options.username(user);
24 }
25
26 if let Some(pass) = settings.pass {
27 options = options.password(pass);
28 }
29
30 if let Some(host) = settings.host {
31 options = options.host(host);
32 }
33
34 if let Some(port) = settings.port {
35 options = options.port(port);
36 }
37
38 options = options.database(settings.db_name);
39
40 if let Some(charset) = settings.charset {
41 options = options.charset(charset);
42 }
43
44 if let Some(dialect) = settings.dialect {
45 options = options.dialect(dialect);
46 }
47
48 if let Some(stmt_cache_size) = settings.stmt_cache_size {
49 options = options.stmt_cache_size(stmt_cache_size);
50 }
51
52 if let Some(role_name) = settings.role_name {
53 options = options.role_name(role_name);
54 }
55
56 Ok(options)
57 }
58}
59
60pub struct ConnStringSettings {
61 pub user: Option<String>,
62 pub pass: Option<String>,
63 pub host: Option<String>,
64 pub port: Option<u16>,
65 pub db_name: String,
66 pub charset: Option<Charset>,
67 pub dialect: Option<Dialect>,
68 pub stmt_cache_size: Option<usize>,
69 pub role_name: Option<String>,
70}
71
72fn parse(url: &Url) -> Result<ConnStringSettings, FbError> {
73 if url.scheme().to_lowercase() != "firebird" {
74 return Err(FbError::from(
75 "The string must start with the prefix 'firebird://'",
76 ));
77 }
78
79 let user = match url.username() {
80 "" => None,
81 u => Some(percent_decode_str(u).decode_utf8()?.into_owned()),
82 };
83
84 let pass = match url.password() {
85 Some(p) => Some(percent_decode_str(p).decode_utf8()?.into_owned()),
86 _ => None,
87 };
88
89 let mut host = match url.host_str() {
90 Some(h) => Some(percent_decode_str(h).decode_utf8()?.into_owned()),
91 _ => None,
92 };
93
94 let port = url.port();
95
96 let mut db_name = match url.path() {
97 "" => None,
98 db => {
99 let db = percent_decode_str(db).decode_utf8()?.into_owned();
100 if db.starts_with('/') && url.has_host() {
101 Some(db.replacen('/', "", 1))
102 } else {
103 Some(db)
104 }
105 },
106 };
107
108 match (&host, &db_name) {
109 (Some(h), Some(db)) => {
119 if h.len() == 1 && user.is_none() && pass.is_none() && port.is_none() {
120 db_name = Some(format!("{}:/{}", h, db));
121 host = None;
122 }
123 },
124 (Some(h), None) => {
133 if user.is_none() && pass.is_none() && port.is_none() {
134 db_name = Some(h.to_string());
135 host = None;
136 }
137 },
138 _ => {},
139 }
140
141 let db_name = db_name.ok_or_else(|| FbError::from("The database name/path is required"))?;
142
143 let mut dialect = None;
144 let mut charset = None;
145 let mut stmt_cache_size = None;
146 let mut role_name = None;
147
148 for (param, val) in url.query_pairs() {
149 match param.to_string().as_str() {
150 "dialect" => {
151 dialect = match Dialect::from_str(&val) {
152 Ok(d) => Some(d),
153 _ => None,
154 };
155 },
156 "charset" => {
157 charset = match Charset::from_str(&val) {
158 Ok(d) => Some(d),
159 _ => None,
160 };
161 },
162 "stmt_cache_size" => {
163 stmt_cache_size = match val.parse::<usize>() {
164 Ok(v) => Some(v),
165 _ => None,
166 };
167 },
168 "role_name" => {
169 if val != "" {
170 role_name = Some(val.to_string());
171 }
172 },
173 _ => {},
174 }
175 }
176
177 Ok(ConnStringSettings {
178 user,
179 pass,
180 host,
181 port,
182 db_name,
183 charset,
184 dialect,
185 stmt_cache_size,
186 role_name,
187 })
188}
189
190impl FromStr for FbConnectOptions {
191 type Err = Error;
192
193 fn from_str(url: &str) -> Result<Self, Self::Err> {
194 let url = Url::parse(url).map_err(Error::config)?;
195 Self::parse_from_url(&url)
196 }
197}