rbatis

Rust Compile Time ORM robustness,async, pure Rust Dynamic SQL

APACHE-2.0 License

Downloads
1.1M
Stars
2.3K
Committers
25

Bot releases are hidden (Show)

rbatis - v2.0.4

Published by zhuxiujia over 3 years ago

v2.0.4

  • #[py_sql] and #[html_sql] not need define database type

for now

    #[py_sql(RB, "select * from biz_activity where delete_flag = 0
                  if name != '':
                    and name=#{name}")]
    async fn py_select_page(page_req: &PageRequest, name: &str) -> Page<BizActivity> { todo!() }

befor(Only the 2.0.3 version)

    #[py_sql(RB, "select * from biz_activity where delete_flag = 0
                  if name != '':
                    and name=#{name}","mysql")]
    async fn py_select_page(page_req: &PageRequest, name: &str) -> Page<BizActivity> { todo!() }
rbatis - v2.0.3

Published by zhuxiujia over 3 years ago

v2.0.3

  • Important update (pysql removes runtime, directly compiles to static rust code) This means that the performance of SQL generated using py_sql,html_sql is roughly similar to that of handwritten code.

Because of the compile time, the annotations need to declare the database type to be used

    #[py_sql(
    rb,
    "select * from biz_activity where delete_flag = 0
                  if name != '':
                    and name=#{name}","mysql")]
    async fn py_sql_tx(rb: &Rbatis, tx_id: &String, name: &str) -> Vec<BizActivity> { todo!() }
  • Added html_sql support, a form of organization similar to MyBatis, to facilitate migration of Java systems to Rust(Note that it is also compiled as Rust code at build time and performs close to handwritten code) this is very faster

Because of the compile time, the annotations need to declare the database type to be used

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "https://github.com/rbatis/rbatis_sql/raw/main/mybatis-3-mapper.dtd">
<mapper>
    <select id="select_by_condition">
        select * from biz_activity where
        <if test="name != ''">
            name like #{name}
        </if>
    </select>
</mapper>
    ///select page must have  '?:&PageRequest' arg and return 'Page<?>'
    #[html_sql(rb, "example/example.html","mysql")]
    async fn select_by_condition(rb: &mut RbatisExecutor<'_>, page_req: &PageRequest, name: &str) -> Page<BizActivity> { todo!() }

rbatis - v2.0.2

Published by zhuxiujia over 3 years ago

v2.0.2

  • remove id,id_name( Use Column dynamic fields in place of static methods)
    for example:
rb.fetch_by_column::<Option<BizActivity>,_>( "id",&"1").await
rb.fetch_by_column::<Option<BizActivity>,_>( "name",&"joke").await
rb.fetch_by_column::<Option<BizActivity>,_>( "age",1).await
  • remove context_id,tx_id,TxManager(Transfers transactions using a transaction structure)
let tx = rb.acquire_begin().await.unwrap();
        let v: serde_json::Value = tx
            .fetch("select count(1) from biz_activity;",&vec![])
            .await
            .unwrap();
        println!("{}", v.clone());
        tx.commit().await.unwrap();

also you can use defer

    pub async fn forget_commit(rb: &Rbatis) -> rbatis::core::Result<serde_json::Value> {
        // tx will be commit.when func end
        let tx = rb.acquire_begin().await?.defer(|tx|{
            println!("tx is drop!");
            async_std::task::block_on(async{ tx.rollback().await; });
        });
        let v: serde_json::Value = tx
            .fetch( "select count(1) from biz_activity;",&vec![])
            .await?;
        return Ok(v);
    }
  • use TableNoLogic to Temporary disable of Plugin
    #[tokio::test]
    pub async fn test_remove_batch_by_id() {
        let mut rb = init_rbatis().await;
        rb.logic_plugin = Some(Box::new(RbatisLogicDeletePlugin::new("delete_flag")));
        rb.link("mysql://root:123456@localhost:3306/test")
            .await
            .unwrap();
        let r = rb
            .remove_batch_by_column::<TableNoLogic<BizActivity>,_>( "id",&["1".to_string(), "2".to_string()])
            .await;
        if r.is_err() {
            println!("{}", r.err().unwrap().to_string());
        }
    }
  • The logical delete plug-in changes to handle only delete methods(The older version handles delete and query methods)

V2.0 can't be without your support,thanks

rbatis - v1.8.88

Published by zhuxiujia over 3 years ago

v1.8.88

  • try fix tx deadlock
rbatis - v1.8.87

Published by zhuxiujia over 3 years ago

v1.8.87

  • try Fix #104 #103 deadlock
  • Fix procedure macro warning
rbatis - v1.8.85

Published by zhuxiujia over 3 years ago

  • fix #102 Use DashMap instead to reduce lock granularity
rbatis - v1.8.84

Published by zhuxiujia over 3 years ago

v1.8.84

  • up sqlx-core version
rbatis - v1.8.83

Published by zhuxiujia over 3 years ago

v1.8.83

fix #93

rbatis - v1.8.82

Published by zhuxiujia over 3 years ago

v1.8.82

  • fix #91
rbatis - v1.8.81

Published by zhuxiujia over 3 years ago

v1.8.81

  • The main runtime switch is async_std, Fix incompatibilities
  • add choose runtime future(tokio1,tokio02,tokio03,async-io) for example:
rbatis = { version = "1.8.81", default-features = false, features = ["mysql","tokio1"] }
rbatis - v1.8.80

Published by zhuxiujia over 3 years ago

v1.8.80

  • 【rbatis-macro-driver】Fixed type inference error caused by unclear type definition
rbatis - v1.8.79

Published by zhuxiujia over 3 years ago

v1.8.79

  • API using tokio(delete async_std dep),But you can still use async_std::** run rbatis (compatible)
  • Optimize transaction manager shutdown using atomic bool
  • The database features switch changes to all-database,mssql,mysql,postgres, sqlite
rbatis - v1.8.78

Published by zhuxiujia over 3 years ago

v1.8.78

  • fix sql or py_sql macro upper_case_sql_keyword feature enable's bug
  • add plugin BlockAttackDeleteInterceptor and BlockAttackUpdateInterceptor
    When operating on the database, especially the management authority (usually SA account) to operate on the data, there may be no attention to conditions in the operation process, resulting in the full table operation, such as:

1, delete,
delete from tablename
2, update,
update tablename set columnname = value

  • add plugin for RbatisLogFormatSqlIntercept for example:
    /// Formatting precompiled SQL
    ///
    /// [] Exec  ==> insert into biz_activity (id,name,pc_link,h5_link,pc_banner_img,h5_banner_img,sort,status,remark,create_time,version,delete_flag)
    /// values (?,?,?,?,?,?,?,?,?,?,?,?)
    ///
    /// into
    ///
    /// [rbatis] [] [format_sql]insert into biz_activity (id,name,pc_link,h5_link,pc_banner_img,h5_banner_img,sort,status,remark,create_time,version,delete_flag)
    /// values ("12312","12312",null,null,null,null,"1",1,null,"2021-03-10T20:34:47.432751100",1,1)
    #[async_std::test]
    pub async fn test_show_format_sql() {
        fast_log::init_log("requests.log", 1000, log::Level::Info, None, true);
        let mut rb = Rbatis::new();
        rb.add_sql_intercept(RbatisLogFormatSqlIntercept{});
        rb.link("mysql://root:123456@localhost:3306/test")
            .await
            .unwrap();
        let activity = BizActivity {
            id: Some("12312".to_string()),
            name: Some("12312".to_string()),
            pc_link: None,
            h5_link: None,
            pc_banner_img: None,
            h5_banner_img: None,
            sort: Some("1".to_string()),
            status: Some(1),
            remark: None,
            create_time: Some(NaiveDateTime::now()),
            version: Some(1),
            delete_flag: Some(1),
        };
        let r = rb.save("", &activity).await;
    }
  • fix no return problem when interceptors return errors
rbatis - v1.8.77

Published by zhuxiujia over 3 years ago

v1.8.77

  • crud.rs add method save_batch_slice
    for example:
//One-time insert
rb.save_batch_slice("",&vec![activity],0).await;
// insert 10 vec data every time Until all inserts are done
rb.save_batch_slice("",&vec![activity],10).await;
  • add feature upper_case_sql_keyword(default is lower sql keyword case)
  • fix version lock plugin(Optimistic locking) with incorrect SQL generation
rbatis - v1.8.76

Published by zhuxiujia over 3 years ago

v1.8.76

  • add macro(make_table,make_table_field_vec,make_table_field_map),
    make_table Simplifies table construction by relying on the Default trait
    make_table_field_vec take the target Vec member attribute Vec collection
    make_table_field_map Gets the HashMap collection of member attributes of the target Vec
    for example:
    #[crud_enable]
    #[derive(Clone, Debug)]
    pub struct BizActivity {
        pub id: Option<String>,
        pub name: Option<String>,
        pub pc_link: Option<String>,
        pub h5_link: Option<String>,
        pub pc_banner_img: Option<String>,
        pub h5_banner_img: Option<String>,
        pub sort: Option<String>,
        pub status: Option<i32>,
        pub remark: Option<String>,
        pub create_time: Option<NaiveDateTime>,
        pub version: Option<BigDecimal>,
        pub delete_flag: Option<i32>,
    }

    impl Default for BizActivity {
        fn default() -> Self {
            Self {
                id: None,
                name: None,
                pc_link: None,
                h5_link: None,
                pc_banner_img: None,
                h5_banner_img: None,
                sort: None,
                status: None,
                remark: None,
                create_time: None,
                version: None,
                delete_flag: None,
            }
        }
    }

    #[test]
    fn test_make_table() {
        let table = rbatis::make_table!(BizActivity{
              id:"1".to_string(),
        });
        println!("{:#?}", table);
    }

    #[test]
    fn test_table_field_map() {
        let table = rbatis::make_table!(BizActivity{
              id:"1".to_string(),
              name:"a".to_string()
        });
        let table_vec = vec![table];
        let map = rbatis::make_table_field_map!(&table_vec,name);
        println!("{:#?}", map);
        assert_eq!(map.len(), table_vec.len());
    }

    #[test]
    fn test_table_field_vec() {
        let table = rbatis::make_table!(BizActivity{
              id:"1".to_string(),
              name:"a".to_string()
        });
        let table_vec = vec![table];
        let names = rbatis::make_table_field_vec!(&table_vec,name);
        println!("{:#?}", names);
        assert_eq!(names.len(), table_vec.len());
    }
  • add FatherChildRelationship trait, support Parent-child relational mapping
    for example:
    #[crud_enable]
    #[derive(Clone, Debug)]
    pub struct FatherChildVO {
        pub id: Option<i32>,
        pub father_id: Option<i32>,
        pub childs: Vec<FatherChildVO>,
    }

    impl FatherChildRelationship for FatherChildVO {
        fn get_father_id(&self) -> Option<&Self::IdType> {
            self.father_id.as_ref()
        }
        fn set_childs(&mut self, arg: Vec<Self>) {
            self.childs = arg;
        }
    }

    #[test]
    fn test_to_father_child_relationship() {
        let mut father = FatherChildVO {
            id: Some(1),
            father_id: None,
            childs: vec![],
        };
        let child = FatherChildVO {
            id: Some(2),
            father_id: Some(1),
            childs: vec![],
        };
        // or childs = rbatis.fetch_list****() get all of  childs data.
        let childs=vec![child];
        let all_record = rbatis::make_table_field_map!(childs,id);
        father.recursive_set_childs(&all_record);
        println!("{:#?}", father);
    }
FatherChildVO {
    id: Some(
        1,
    ),
    father_id: None,
    childs: [
        FatherChildVO {
            id: Some(
                2,
            ),
            father_id: Some(
                1,
            ),
            childs: [],
        },
    ],
}
rbatis - v1.8.75

Published by zhuxiujia over 3 years ago

v1.8.75

  • remove the feature["snowflake"] and rustflake crate dep. Change to the built-in Lock-Free impl snowflake Plugin
    for example:
//old impl
// let id = rbatis::plugin::snowflake::async_snowflake_id() .await.to_string();
//new impl
let id = rbatis::plugin::snowflake::new_snowflake_id().to_string();
println!("{}",id);
//205667537625681919

In My computer The new (77ns/op) snowflake is 40% to 50% faster than the old (113ns/op) snowflake algorithm because the runtime context switch is bound to take time, plus the impact time of parking_lot's mutex blocking

  • add object_id plugin(Copy from the bson-rust)
 println!("{}",rbatis::plugin::object_id::ObjectId::new().to_string());
//603c86e400299f5900d378b4
rbatis - v1.8.74

Published by zhuxiujia over 3 years ago

v1.8.74

  • rbatis log plugin will be print error log
  • py_sql and sql macro allow Load SQL files dynamically(In debug mode, rewrite the SQL to avoid duplicate compilation)see example/py_sql_test.rs

first , define py_sql.sql

select * from biz_activity where delete_flag = 0
    if name != '':
      and name=#{name}

then,load file

///load from file
    fn load_file_str(file_name:&str)->String{
        let mut f =File::open(file_name).unwrap();
        let mut s=String::new();
        f.read_to_string(&mut s);
        return s;
    }

    ///load file py_sql(Each read file changes every time)
    #[py_sql(rb, load_file_str("py_sql.sql"))]
    async fn py_select_file(rb: &Rbatis, page_req: &PageRequest, name: &str) -> Page<BizActivity> {}

    lazy_static!(
     pub static ref PY_SQL_FILE_STR:String=load_file_str("py_sql.sql");
    );

    ///load file py_sql(only load file once)
    #[py_sql(rb, PY_SQL_FILE_STR)]
    async fn py_select_file_static(rb: &Rbatis, page_req: &PageRequest, name: &str) -> Page<BizActivity> {}

    /// test load py_sql from file
    #[async_std::test]
    pub async fn test_py_select_file() {
        fast_log::init_log("requests.log", 1000, log::Level::Info, None, true);
        //use static ref
        let rb = Rbatis::new();
        rb.link("mysql://root:123456@localhost:3306/test")
            .await
            .unwrap();

        let mut result = py_select_file(&rb, &PageRequest::new(1, 10), "test")
            .await
            .unwrap();
        println!("{:?}", result);

        result = py_select_file_static(&rb, &PageRequest::new(1, 10), "test")
            .await
            .unwrap();
        println!("{:?}", result);
    }
rbatis - v1.8.73

Published by zhuxiujia over 3 years ago

v1.8.72

  • add method is_debug_mode() method,Used to check if DEBUG is enabled
  • crud.rs add method fetch_count_by_wrapper(context_id: &str, w: &Wrapper) method
  • Most plugins support send context_id
  • Support for plug-in disable(Using context_id) for example:
#[cfg(test)]
mod test {
    use rbatis::rbatis::Rbatis;
    use rbatis::plugin::logic_delete::RbatisLogicDeletePlugin;
    use crate::BizActivity;
    use rbatis::crud::CRUD;
    use chrono::NaiveDateTime;
    use rbatis::core::value::DateTimeNow;
    #[async_std::test]
    async fn plugin_exclude(){
        fast_log::init_log("requests.log", 1000, log::Level::Info, None, true);
        let mut rb = Rbatis::new();
        let mut plugin=RbatisLogicDeletePlugin::new("delete_flag");
        plugin.excludes.push("disable_del:".to_string());
        plugin.excludes.push("tx:disable_del:".to_string());
        rb.set_logic_plugin(Some(plugin));
        rb.link("mysql://root:123456@localhost:3306/test")
            .await
            .unwrap();

        let id="12312".to_string();
        //logic delete sql:   "UPDATE biz_activity SET delete_flag = 1 WHERE id = ?"
        rb.remove_by_id::<BizActivity>("", &id).await;
        //delete sql          "DELETE FROM biz_activity WHERE id = ?"
        rb.remove_by_id::<BizActivity>("disable_del:", &id).await;
}
rbatis - v1.8.72

Published by zhuxiujia over 3 years ago

v1.8.72

  • Repeal this version! Please use the latest version
rbatis - v1.8.71

Published by zhuxiujia over 3 years ago

v1.8.71

  • Page Plugin edit arg page to page_no, size to page_size,current to page_no
  • runtime mod edit to use async_std::*
  • remove fetch_prepare_wrapper and exec_prepare_wrapper method