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}