db-cores 0.1.0

Database core utilities
Documentation

#[macro_export]
macro_rules! define_model {
    // ident为标识符, expr是表达式,
    ($struct:ident,
     $table_name:expr,
    $(
        $(#[$field_attr:meta])*
        $column:ident : $type:ty
    ),* $(,)?

    ) => {
        
        #[allow(unused_attributes)]
        #[derive(Debug, $crate::serde::Serialize, $crate::serde::Deserialize, $crate::db_proc_macro::ToFields, $crate::db_proc_macro::ToOption, Clone)] //::app_macro::ToOption,
        #[cfg_attr(any(feature = "postgres", feature = "mysql", feature = "sqlite"), derive($crate::sqlx::FromRow))]
        pub struct $struct {
            $(
                $(#[$field_attr])*
                pub $column: $type,
            )*
        }

        impl $struct {
            #[allow(dead_code)]
            pub const NAME: &'static str = $table_name;
            /// 系统字段:更新时间戳
            #[allow(dead_code)]
            pub fn update_time(&mut self) {
                //  前端一律不上传 created_at, 由数据库自动生成
                let now = $crate::utlis::_utc_ms_option();
                $( if stringify!($column) == "updated_at" {
                    self.updated_at = now;
                } )*
            }
            // 返加postgres 加上 schema的table名
            #[allow(dead_code)]
            pub fn pg_table(schema:&str)->String{
                if !schema.is_empty() {
                    format!("\"{}\".\"{}\"" , schema, Self::NAME)
                } else {
                    format!("\"{}\"" , Self::NAME)
                }
            }
        }
    }
}


#[macro_export]
macro_rules! define_enum {
    // 定义宏规则
    (
        $(#[$enum_attr:meta])*
        $vis:vis enum $name:ident {
            $(
                $(#[$variant_attr:meta])*
                $variant:ident = $value:expr
            ),* $(,)?
        }
    ) => {
        // 定义枚举
        $(#[$enum_attr])*
        // #[derive(Debug, Clone)]
        $vis enum $name {
            $(
                $(#[$variant_attr])*
                $variant,
            )*
        }

        impl $name {
            pub fn to_str(&self) -> &'static str {
                match self {
                    $(
                        $name::$variant => $value,
                    )*
                }
            }
        }

        // 实现 FromStr  s.parse() 就是调用了 FromStr trait 的 from_str 方法
        impl ::std::str::FromStr for $name {
            type Err = String;
            fn from_str(s: &str) -> Result<Self, Self::Err> {
                match s {
                    $(
                        $value => Ok($name::$variant),
                    )*
                    _ => Err(format!("Invalid value for {}: {}", stringify!($name), s)),
                }
            }
        }

        // 实现 Serialize
        impl $crate::serde::Serialize for $name {  // 从结构 序列化 成 json时才会调用
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: $crate::serde::Serializer,
            {
                let value = match self {
                    $(
                        $name::$variant => $value,
                    )*
                };
                serializer.serialize_str(value)
            }
        }


        // 实现 Deserialize  当sqlx 解析son内容时会调用
        impl<'de> $crate::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: $crate::serde::Deserializer<'de>,
            {
                let s = String::deserialize(deserializer)?;
                match s.as_str() {
                    $(
                        $value => Ok($name::$variant),
                    )*
                    _ => Err(::serde::de::Error::custom(
                        format!(concat!("Invalid value for ", stringify!($name), ": {}"), s))),
                }
            }
        }


        // $crate::sqlx  前提是lib 有  pub use sqlx;
        #[cfg(feature = "sqlite")]
        impl<'r> $crate::sqlx::Decode<'r, $crate::sqlx::Sqlite> for $name {
            fn decode(value: $crate::sqlx::sqlite::SqliteValueRef<'r>) -> Result<Self, $crate::sqlx::error::BoxDynError> {
                let value_str = <String as $crate::sqlx::Decode<$crate::sqlx::Sqlite>>::decode(value)?;
                $name::from_str(&value_str).map_err(|e| e.into()) //
            }
        }

        #[cfg(feature = "mysql")]
        impl<'r> $crate::sqlx::Decode<'r, $crate::sqlx::MySql> for $name {
            fn decode(value: $crate::sqlx::mysql::MySqlValueRef<'r>) -> Result<Self, $crate::sqlx::error::BoxDynError> {
                let value_str = <String as $crate::sqlx::Decode<$crate::sqlx::MySql>>::decode(value)?;
                $name::from_str(&value_str).map_err(|e| e.into())
            }
        }

        #[cfg(feature = "postgres")]
        impl<'r> $crate::sqlx::Decode<'r, $crate::sqlx::Postgres> for $name {
            fn decode(value: $crate::sqlx::postgres::PgValueRef<'r>) -> Result<Self, $crate::sqlx::error::BoxDynError> {
                let value_str = <String as $crate::sqlx::Decode<$crate::sqlx::Postgres>>::decode(value)?;
                $name::from_str(&value_str).map_err(|e| e.into())
            }
        }

        #[cfg(feature = "sqlite")]
        impl $crate::sqlx::Type<$crate::sqlx::Sqlite> for $name {
            fn type_info() -> $crate::sqlx::sqlite::SqliteTypeInfo {
                <String as $crate::sqlx::Type<$crate::sqlx::Sqlite>>::type_info()
            }
        }

        #[cfg(feature = "postgres")]
        impl $crate::sqlx::Type<$crate::sqlx::Postgres> for $name {
            fn type_info() -> $crate::sqlx::postgres::PgTypeInfo  {
                <String as $crate::sqlx::Type<$crate::sqlx::Postgres>>::type_info()
            }
        }

        #[cfg(feature = "mysql")]
        impl $crate::sqlx::Type<$crate::sqlx::MySql> for $name {
            fn type_info() -> $crate::sqlx::mysql::MySqlTypeInfo{
                <String as $crate::sqlx::Type<$crate::sqlx::MySql>>::type_info()
            }
        }
    };
}



#[cfg(feature = "postgres")]
#[macro_export]
macro_rules! pg_builder {
    //  第一个参数为Sql str,  第二个参数 匹配方括号写法: 编译期已知参数列表 [expr, expr, ...]
    ($sql:expr, [$($param:expr),* $(,)?]) => {{
        use ::regex::Regex;
        use ::sqlx::QueryBuilder;
        let sql_str = $sql.as_ref();
        let re = Regex::new(r"(\?|\$\d+)").unwrap();
        let parts: Vec<&str> = re.split(sql_str).collect();
        let param_count = 0 $( + { let _ = &$param; 1 } )*;
        if parts.len() != param_count + 1 {panic!("参数数量与 SQL 占位符数量不匹配: 发现 {} 个占位符, 提供了 {} 个参数",parts.len() - 1, param_count ); }
        let mut builder: QueryBuilder<'_, ::sqlx::postgres::Postgres> = QueryBuilder::new("");
        let mut _i = 0;
        $(
            builder.push(parts[_i]);
            builder.push_bind(&$param);
            _i += 1;
        )*
        builder.push(parts[_i]);
        builder
    }};

    //  第一个参数为Sql str,  第二参数 匹配运行时参数容器:Vec<T> 或 &[T]
    ($sql:expr, $params:expr) => {{
        use ::regex::Regex;
        use ::sqlx::QueryBuilder;
        let sql_str = $sql.as_ref(); // 这样可以兼容String和 &str
        let re = Regex::new(r"(\?|\$\d+)").unwrap();
        let parts: Vec<&str> = re.split(sql_str).collect();
        let params_ref = &$params; // 引用 Vec/切片
        let param_count = params_ref.len();
        if parts.len() != param_count + 1 {
            panic!( "参数数量与 SQL 占位符数量不匹配: 发现 {} 个占位符, 提供了 {} 个参数", parts.len() - 1, param_count);
        }
        let mut builder: QueryBuilder<'_, ::sqlx::postgres::Postgres> = QueryBuilder::new("");
        for (i, value) in params_ref.iter().enumerate() {
            builder.push(parts[i]);
            builder.push_bind(&*value);
        }
        builder.push(parts[param_count]);
        builder
    }};
}

// 这个怎么实现     let a = pg_builder!(sql, [b,aa]);  []作用是为了与 sql区别,并不是要传入一个数组切版
#[cfg(feature = "postgres")]
#[test]
fn dev() {
    let sql = "select * from talbe where id=$1 and  stre=$2";
    let _b = 34;

    let _aa = "adsb".to_string();
    let veca = [34, 3434];
    let a = pg_builder!(sql, veca);
    let a = a.sql();

    println!("asfd {a}");
}