tiny_web/sys/dbs/adapter.rs
1use std::sync::Arc;
2
3#[cfg(feature = "pgsql")]
4use postgres::types::ToSql;
5
6use rustls::{
7 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
8 pki_types::{CertificateDer, ServerName, UnixTime},
9 DigitallySignedStruct, SignatureScheme,
10};
11#[cfg(feature = "mssql")]
12use tiberius::ToSql;
13
14#[cfg(not(any(feature = "pgsql", feature = "mssql")))]
15use super::without_sql::ToSql;
16
17use tokio::sync::{Mutex, Semaphore};
18
19use crate::sys::{data::Data, init::DBConfig, log::Log};
20
21#[cfg(feature = "pgsql")]
22use super::pgsql::PgSql;
23
24#[cfg(feature = "mssql")]
25use super::mssql::MsSql;
26
27#[cfg(not(any(feature = "pgsql", feature = "mssql")))]
28use super::without_sql::WithoutSql;
29
30#[cfg(feature = "pgsql")]
31type QueryParam<'a> = &'a [&'a (dyn ToSql + Sync)];
32
33#[cfg(feature = "mssql")]
34type QueryParam<'a> = &'a [&'a dyn ToSql];
35
36#[cfg(not(any(feature = "pgsql", feature = "mssql")))]
37type QueryParam<'a> = &'a [&'a dyn ToSql];
38
39/// Pool of database connections for asynchronous work.
40///
41/// # Values
42///
43/// * `connections: Vec<Arc<Mutex<DB>>>` - Vector of database connections;
44/// * `semaphore: Arc<Semaphore>` - Semaphore for finding free connection;
45/// * `size: usize` - Number of connected databases.
46#[derive(Debug)]
47pub struct DB {
48 /// Vector of database connections.
49 #[cfg(feature = "pgsql")]
50 connections: Vec<Arc<Mutex<PgSql>>>,
51 /// Vector of database connections.
52 #[cfg(feature = "mssql")]
53 connections: Vec<Arc<Mutex<MsSql>>>,
54 /// Vector of database connections.
55 #[cfg(not(any(feature = "pgsql", feature = "mssql")))]
56 connections: Vec<Arc<Mutex<WithoutSql>>>,
57 /// Semaphore for finding free connection.
58 semaphore: Arc<Semaphore>,
59 /// The database is in use
60 is_used: bool,
61}
62
63impl DB {
64 /// Initialize pool of database connections for asynchronous work.
65 ///
66 /// # Parameters
67 ///
68 /// * `size: usize` - Pool size; =0 - when install mode
69 /// * `config: Arc<DBConfig>` - Configuration.
70 ///
71 /// # Return
72 ///
73 /// New poll of database connections for asynchronous work.
74 pub(crate) async fn new(size: usize, config: Arc<DBConfig>) -> Option<DB> {
75 let mut connections = Vec::with_capacity(size);
76 let mut asize = 0;
77 for _ in 0..size {
78 #[cfg(feature = "pgsql")]
79 let mut db = PgSql::new(Arc::clone(&config))?;
80 #[cfg(feature = "mssql")]
81 let mut db = MsSql::new(Arc::clone(&config))?;
82 #[cfg(not(any(feature = "pgsql", feature = "mssql")))]
83 let mut db = WithoutSql::new(Arc::clone(&config))?;
84 if db.connect().await {
85 asize += 1;
86 connections.push(Arc::new(Mutex::new(db)));
87 } else {
88 Log::stop(610, None);
89 return None;
90 }
91 }
92 let semaphore = Arc::new(Semaphore::new(asize));
93
94 Some(DB {
95 connections,
96 semaphore,
97 is_used: asize > 0,
98 })
99 }
100 /// Is library uses database
101 pub fn in_use(&self) -> bool {
102 self.is_used
103 }
104
105 pub(crate) async fn check_db(config: &DBConfig, sql: Option<Vec<String>>) -> Result<String, String> {
106 #[cfg(feature = "pgsql")]
107 return PgSql::check_db(config, sql).await;
108
109 #[cfg(feature = "mssql")]
110 return MsSql::check_db(config, sql).await;
111
112 #[cfg(not(any(feature = "pgsql", feature = "mssql")))]
113 return Ok(String::new());
114 }
115
116 /// Execute query to database synchronously
117 ///
118 /// # Parmeters
119 ///
120 /// * `query: &str` - SQL query;
121 /// * `params: &[&(dyn ToSql + Sync)]` - Array of params. (for PgSql)
122 /// * `params: &[&dyn ToSql]` - Array of params. (for MsSql)
123 /// * `assoc: bool` - Return columns as associate array if True or Vecor id False.
124 ///
125 /// # Return
126 ///
127 /// * `Option::None` - When error query or diconnected;
128 /// * `Option::Some(Vec<Data::Map>)` - Results, if assoc = true.
129 /// * `Option::Some(Vec<Data::Vec>)` - Results, if assoc = false.
130 pub async fn query<'a>(&self, query: &str, params: QueryParam<'a>, assoc: bool) -> Option<Vec<Data>> {
131 if !self.is_used {
132 return None;
133 }
134
135 let permit = match self.semaphore.acquire().await {
136 Ok(p) => p,
137 Err(e) => {
138 Log::warning(606, Some(e.to_string()));
139 return None;
140 }
141 };
142 for connection_mutex in &self.connections {
143 if let Ok(mut db) = connection_mutex.try_lock() {
144 let res = db.query(&query, params, assoc).await;
145 drop(permit);
146 return res;
147 };
148 }
149 drop(permit);
150 Log::warning(607, None);
151 None
152 }
153
154 pub(crate) async fn query_prepare<'a>(&self, query: i64, params: QueryParam<'a>, assoc: bool) -> Option<Vec<Data>> {
155 if !self.is_used {
156 return None;
157 }
158
159 let permit = match self.semaphore.acquire().await {
160 Ok(p) => p,
161 Err(e) => {
162 Log::warning(606, Some(e.to_string()));
163 return None;
164 }
165 };
166 for connection_mutex in &self.connections {
167 if let Ok(mut db) = connection_mutex.try_lock() {
168 let res = db.query(&query, params, assoc).await;
169 drop(permit);
170 return res;
171 };
172 }
173 drop(permit);
174 Log::warning(607, None);
175 None
176 }
177
178 /// Execute query to database synchronously without results
179 ///
180 /// # Parmeters
181 ///
182 /// * `query: &str` - SQL query;
183 /// * `params: &[&(dyn ToSql + Sync)]` - Array of params. (for PgSql)
184 /// * `params: &[&dyn ToSql]` - Array of params. (for MsSql)
185 ///
186 /// # Return
187 ///
188 /// * `Option::None` - When error query or diconnected;
189 /// * `Option::Some(())` - Successed.
190 pub async fn execute<'a>(&self, query: &str, params: QueryParam<'a>) -> Option<()> {
191 if !self.is_used {
192 return None;
193 }
194
195 let permit = match self.semaphore.acquire().await {
196 Ok(p) => p,
197 Err(e) => {
198 Log::warning(606, Some(e.to_string()));
199 return None;
200 }
201 };
202 for connection_mutex in &self.connections {
203 if let Ok(mut db) = connection_mutex.try_lock() {
204 let res = db.execute(&query, params).await;
205 drop(permit);
206 return res;
207 };
208 }
209 drop(permit);
210 Log::warning(607, None);
211 None
212 }
213
214 pub(crate) async fn execute_prepare<'a>(&self, query: i64, params: QueryParam<'a>) -> Option<()> {
215 if !self.is_used {
216 return None;
217 }
218
219 let permit = match self.semaphore.acquire().await {
220 Ok(p) => p,
221 Err(e) => {
222 Log::warning(606, Some(e.to_string()));
223 return None;
224 }
225 };
226 for connection_mutex in &self.connections {
227 if let Ok(mut db) = connection_mutex.try_lock() {
228 let res = db.execute(&query, params).await;
229 drop(permit);
230 return res;
231 };
232 }
233 drop(permit);
234 Log::warning(607, None);
235 None
236 }
237
238 /// Execute query to database and return a result,
239 /// and grouping tabular data according to specified conditions.
240 ///
241 /// # Parmeters
242 ///
243 /// * `query: &str` - SQL query;
244 /// * `params: &[&(dyn ToSql + Sync)]` - Array of params. (for PgSql)
245 /// * `params: &[&dyn ToSql]` - Array of params. (for MsSql)
246 /// * `assoc: bool` - Return columns as associate array if True or Vecor id False.
247 /// * `conds: Vec<Vec<&str>>` - Grouping condition.
248 ///
249 /// Grouping condition:
250 /// * The number of elements in the first-level array corresponds to the hierarchy levels in the group.
251 /// * The number of elements in the second-level array corresponds to the number of items in one hierarchy. The first element of the group (index=0) is considered unique.
252 /// * &str - field names for `Data::Vec<Data::Map<...>>`.
253 ///
254 /// The first value in the second-level array must be of type `Data::I64`.
255 ///
256 /// For each group, a new field with the name `sub` (encoded using `fnv1a_64`) will be created, where child groups will be located.
257 ///
258 /// If the data does not match the format `Data::Vec<Data::Map<...>>`, grouping will not occur, `Option::None` will be returned.
259 /// If the data does not match the tabular format, grouping will not occur, `Option::None` will be returned.
260 ///
261 /// Fields that are not included in the group will be excluded.
262 ///
263 /// # Return
264 /// * Option::None - If the fields failed to group.
265 /// ## if assoc = true
266 /// * `Some(Data::Map<cond[0][0], Data::Map<...>>)` in hierarchical structure.
267 ///
268 /// `struct
269 /// value=Data::Map
270 /// ├── [value1 from column_name=cond[0][0]] => [value=Data::Map] : The unique value of the grouping field
271 /// │ ├── [key=cond[0][0]] => [value1 from column_name=cond[0][0]] : The unique value of the grouping field
272 /// │ ├── [key=cond[0][1]] => [value from column_name=cond[0][1]]
273 /// │ │ ...
274 /// │ ├── [key=cond[0][last]] => [value from column_name=cond[0][last]]
275 /// │ └── [key="sub"] => [value=Data::Map] : (encoded using fnv1a_64)
276 /// │ ├── [value1 from column_name=cond[1][0]] => [value=Data::Map] : The unique value of the grouping field
277 /// │ │ ├── [cond[1][0]] => [value1 from column_name=cond[1][0]] : The unique value of the grouping field
278 /// │ │ ├── [cond[1][1]] => [value from column_name=cond[1][1]]
279 /// │ │ │ ...
280 /// │ │ ├── [cond[0][last]] => [value from column_name=cond[1][last]]
281 /// │ │ └── [key="sub"] => [value Data::Map] : (encoded using fnv1a_64)
282 /// │ └── [value2 from column_name=cond[1][0]] => [value=Data::Map] : The unique value of the grouping field
283 /// │ │ ...
284 /// ├── [value2 from column_name=cond[0][0]] => [value=Data::Map] : The unique value of the grouping field
285 /// │ ├── [key=cond[0][0]] => [value2 from column_name=cond[0][0]] : The unique value of the grouping field
286 /// │ ├── [key=cond[0][1]] => [value from column_name=cond[0][1]]
287 /// │ │ ...
288 /// │ ├── [key=cond[0][last]] => [value from column_name=cond[0][last]]
289 /// │ ├── [key="sub"] => [value Data::Map] : (encoded using fnv1a_64)
290 /// ...
291 /// `
292 /// ## if assoc = false
293 /// * `Some(Data::Map<cond[0][0], Data::Map<...>>)` in hierarchical structure.
294 ///
295 /// `struct
296 /// value=Data::Map
297 /// ├── [value1 from column_name=cond[0][0]] => [value=Data::Vec] : The unique value of the grouping field
298 /// │ ├── [0] => [value1 from column_name=cond[0][0]] : The unique value of the grouping field
299 /// │ ├── [1] => [value from column_name=cond[0][1]]
300 /// │ │ ...
301 /// │ ├── [last] => [value from column_name=cond[0][last]]
302 /// │ └── [last + 1] => [value=Data::Map] : (encoded using fnv1a_64)
303 /// │ ├── [value1 from column_name=cond[1][0]] => [value=Data::Vec] : The unique value of the grouping field
304 /// │ │ ├── [0] => [value1 from column_name=cond[1][0]] : The unique value of the grouping field
305 /// │ │ ├── [1] => [value from column_name=cond[1][1]]
306 /// │ │ │ ...
307 /// │ │ ├── [last] => [value from column_name=cond[1][last]]
308 /// │ │ └── [last+1] => [value Data::Map] : (encoded using fnv1a_64)
309 /// │ └── [value2 from column_name=cond[1][0]] => [value=Data::Vec] : The unique value of the grouping field
310 /// │ │ ...
311 /// ├── [value2 from column_name=cond[0][0]] => [value=Data::Vec] : The unique value of the grouping field
312 /// │ ├── [0] => [value2 from column_name=cond[0][0]] : The unique value of the grouping field
313 /// │ ├── [1] => [value from column_name=cond[0][1]]
314 /// │ │ ...
315 /// │ ├── [last] => [value from column_name=cond[0][last]]
316 /// │ ├── [last + 1] => [value Data::Map] : (encoded using fnv1a_64)
317 /// ...
318 /// `
319 pub async fn query_group<'a>(
320 &self,
321 query: &str,
322 params: QueryParam<'a>,
323 assoc: bool,
324 conds: &[&[impl StrOrI64OrUSize]],
325 ) -> Option<Data> {
326 if !self.is_used {
327 return None;
328 }
329
330 let permit = match self.semaphore.acquire().await {
331 Ok(p) => p,
332 Err(e) => {
333 Log::warning(606, Some(e.to_string()));
334 return None;
335 }
336 };
337 for connection_mutex in &self.connections {
338 if let Ok(mut db) = connection_mutex.try_lock() {
339 let res = db.query_group(&query, params, assoc, conds).await;
340 drop(permit);
341 return res;
342 }
343 }
344 drop(permit);
345 Log::warning(607, None);
346 None
347 }
348}
349
350/// Trait representing types that can be converted to a query or a key statement.
351pub(crate) trait KeyOrQuery {
352 /// Return key
353 fn to_i64(&self) -> i64;
354 /// Return text of query
355 fn to_str(&self) -> &str;
356 /// If value is key
357 fn is_key(&self) -> bool;
358}
359
360impl KeyOrQuery for i64 {
361 /// Return key
362 fn to_i64(&self) -> i64 {
363 *self
364 }
365
366 /// Return text of query
367 fn to_str(&self) -> &str {
368 "key_statement"
369 }
370
371 fn is_key(&self) -> bool {
372 true
373 }
374}
375
376impl KeyOrQuery for &str {
377 /// Return key
378 fn to_i64(&self) -> i64 {
379 0
380 }
381
382 /// Return text of query
383 fn to_str(&self) -> &str {
384 self
385 }
386
387 fn is_key(&self) -> bool {
388 false
389 }
390}
391
392/// A trait representing types that can be converted to either `i64` or `usize`.
393pub trait StrOrI64OrUSize {
394 /// Converts the implementor to an `i64`.
395 fn to_i64(&self) -> i64;
396
397 /// Converts the implementor to a `usize`.
398 fn to_usize(&self) -> usize;
399}
400
401impl StrOrI64OrUSize for i64 {
402 /// Converts `i64` to itself.
403 fn to_i64(&self) -> i64 {
404 *self
405 }
406
407 /// Converts `i64` to `usize`, always returning `0`.
408 fn to_usize(&self) -> usize {
409 usize::MAX
410 }
411}
412
413impl StrOrI64OrUSize for &str {
414 /// Converts `&str` to an `i64` using the FNV1a hash algorithm.
415 fn to_i64(&self) -> i64 {
416 crate::fnv1a_64(self.as_bytes())
417 }
418
419 /// Converts `&str` to `usize`, always returning `0`.
420 fn to_usize(&self) -> usize {
421 usize::MAX
422 }
423}
424
425impl StrOrI64OrUSize for usize {
426 /// Converts `usize` to `i64`, always returning `0`.
427 fn to_i64(&self) -> i64 {
428 0
429 }
430
431 /// Converts `usize` to itself.
432 fn to_usize(&self) -> usize {
433 *self
434 }
435}
436
437#[derive(Debug)]
438pub struct NoCertificateVerification;
439
440impl ServerCertVerifier for NoCertificateVerification {
441 fn verify_server_cert(
442 &self,
443 _: &CertificateDer<'_>,
444 _: &[CertificateDer<'_>],
445 _: &ServerName<'_>,
446 _: &[u8],
447 _: UnixTime,
448 ) -> Result<ServerCertVerified, rustls::Error> {
449 Ok(ServerCertVerified::assertion())
450 }
451
452 fn verify_tls12_signature(
453 &self,
454 _: &[u8],
455 _: &CertificateDer<'_>,
456 _: &DigitallySignedStruct,
457 ) -> Result<HandshakeSignatureValid, rustls::Error> {
458 Ok(HandshakeSignatureValid::assertion())
459 }
460
461 fn verify_tls13_signature(
462 &self,
463 _: &[u8],
464 _: &CertificateDer<'_>,
465 _: &DigitallySignedStruct,
466 ) -> Result<HandshakeSignatureValid, rustls::Error> {
467 Ok(HandshakeSignatureValid::assertion())
468 }
469
470 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
471 vec![
472 SignatureScheme::RSA_PKCS1_SHA1,
473 SignatureScheme::ECDSA_SHA1_Legacy,
474 SignatureScheme::RSA_PKCS1_SHA256,
475 SignatureScheme::ECDSA_NISTP256_SHA256,
476 SignatureScheme::RSA_PKCS1_SHA384,
477 SignatureScheme::ECDSA_NISTP384_SHA384,
478 SignatureScheme::RSA_PKCS1_SHA512,
479 SignatureScheme::ECDSA_NISTP521_SHA512,
480 SignatureScheme::RSA_PSS_SHA256,
481 SignatureScheme::RSA_PSS_SHA384,
482 SignatureScheme::RSA_PSS_SHA512,
483 SignatureScheme::ED25519,
484 SignatureScheme::ED448,
485 ]
486 }
487}