zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
pub mod mysql_client;
pub mod with_mysql;

pub use mysql_client::*;
pub use with_mysql::*;

use sqlx::mysql::MySqlConnectOptions;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::mysql::MySqlSslMode;

use sqlx::ConnectOptions;
use sqlx::MySql;
use sqlx::Pool;

// use secrecy::ExposeSecret;
// use secrecy::Secret;

#[derive(serde::Deserialize, Clone)]
pub struct MysqlSettings {
    pub enable: Option<bool>,
    pub username: Option<String>,
    pub password: Option<String>,
    pub port: Option<u16>,
    pub host: Option<String>,
    pub database_name: Option<String>,
    pub require_ssl: Option<bool>,
    pub mappers: Option<String>,
}

impl Default for MysqlSettings {
    fn default() -> Self {
        Self {
            enable: Some(false),
            username: Some(String::from("root")),
            password: Some(String::from("Cc")),
            port: Some(3306),
            host: Some(String::from("127.0.0.1")),
            database_name: Some(String::from("mysql")),
            require_ssl: Some(false),
            mappers: Some(String::from("./resources/mappers/**/*.yaml")),
        }
    }
}

impl MysqlSettings {
    pub fn enabled(&self) -> bool {
        self.enable.unwrap_or_default()
    }
    pub fn get(settings: &Option<MysqlSettings>) -> Self {
        let _default = Self::default();

        if settings.is_some() {
            let mut s = settings.clone().unwrap();

            if s.enable.is_none() {
                s.enable = _default.enable;
            }

            if s.username.is_none() {
                s.username = _default.username;
            }

            if s.password.is_none() {
                s.password = _default.password;
            }

            if s.port.is_none() {
                s.port = _default.port;
            }

            if s.host.is_none() {
                s.host = _default.host;
            }

            if s.database_name.is_none() {
                s.database_name = _default.database_name;
            }

            if s.require_ssl.is_none() {
                s.require_ssl = _default.require_ssl;
            }

            if s.mappers.is_none() {
                s.mappers = _default.mappers;
            }

            s
        } else {
            _default
        }
    }

    pub fn connection_string_with_secret(&self) -> String {
        format!(
            "mysql://{}:{}@{}:{}/{}",
            self.username.clone().unwrap(),
            "*******",
            self.host.clone().unwrap(),
            self.port.unwrap(),
            self.database_name.clone().unwrap()
        )
    }

    // Renamed from `connection_string_without_db`
    pub fn without_db(&self) -> MySqlConnectOptions {
        let ssl_mode = if self.require_ssl.unwrap() {
            MySqlSslMode::Required
        } else {
            // Try an encrypted connection, fallback to unencrypted if it fails
            MySqlSslMode::Preferred
        };

        MySqlConnectOptions::new()
            .host(&self.host.clone().unwrap())
            .username(&self.username.clone().unwrap())
            .password(&self.password.clone().unwrap())
            .port(self.port.unwrap())
            .ssl_mode(ssl_mode)
    }

    pub fn with_db(&self) -> MySqlConnectOptions {
        self.without_db()
            .database(&self.database_name.clone().unwrap())
            // .log_statements(log::LevelFilter::Debug)
            .log_statements(log::LevelFilter::Info)
        // .disable_statement_logging()
    }

    pub fn connect(&self) -> Pool<MySql> {
        self.log();

        MySqlPoolOptions::new()
            // .max_connections(self.max_connections)
            // .min_connections(self.min_connections)
            // .max_lifetime(self.max_lifetime)
            // .idle_timeout(self.idle_timeout)
            .acquire_timeout(std::time::Duration::from_secs(2))
            // `connect_lazy_with` instead of `connect_lazy`
            .connect_lazy_with(self.with_db())
    }

    fn log(&self) {
        let line = format!(
            "MySqlConnect: connection_string={}, mappers={}",
            self.connection_string_with_secret(),
            self.mappers.as_deref().unwrap_or_default()
        );

        if !crate::core::cacheable::exists2s(&line) {
            log::info!("{}", line);
            crate::core::cacheable::put2s(&line, "");
        }
    }
}

#[derive(Debug)]
pub enum Ordering {
    Asc(String),
    Desc(String),
}

impl Ordering {
    pub fn order_by(order_by: &str) -> String {
        let order_by: Vec<Ordering> = crate::commons::split_str(order_by, ",".to_string())
            .iter()
            .map(|s| s.trim())
            .map(|s| match s.find(' ') {
                None => Ordering::Asc(s.to_string()),
                Some(i) => {
                    if s[i + 1..].trim().to_lowercase() == "asc" {
                        Ordering::Asc(s[..i].trim().to_string())
                    } else {
                        Ordering::Desc(s[..i].trim().to_string())
                    }
                }
            })
            .collect();

        let mut result = vec![];

        for order in order_by {
            match order {
                Ordering::Asc(field) => {
                    if !field.is_empty() {
                        result.push(format!("{} asc", field))
                    }
                }
                Ordering::Desc(field) => {
                    if !field.is_empty() {
                        result.push(format!("{} desc", field))
                    }
                }
            }
        }

        if result.is_empty() {
            "".to_string()
        } else {
            format!(" ORDER BY {}", result.join(", "))
        }
    }
}