A highly Performant SQL Toolkit and Compile time ORM Library. An async, pure Rust SQL crate featuring compile-time Dynamic SQL
It is an ORM, a small compiler, a dynamic SQL languages
- Compatible with most mybatis3 syntax
- No Runtimes,No Garbage Collection,High performance, Based on Future/Tokio
- Zero cost Dynamic SQL, implemented using (proc-macro,compile-time,Cow(Reduce unnecessary cloning)) techniques。 don't need ONGL engine(mybatis)
- JDBC-like driver design, driver use cargo.toml dependency and
Box<dyn Driver>
separation - All database drivers supported
#{arg}
,${arg}
,?
placeholder(pg/mssql auto processing '?' to '$1' and '@P1') - Dynamic SQL(Write code freely in SQL),pagination,
py_sql
query lang andhtml_sql
(Inspired Mybatis). - Dynamic configuration connection pool(Based on the mobc)
- Supports logging, customizable logging based on
log
crate - 100% Safe Rust with
#![forbid(unsafe_code)]
enabled - Support use Trait System Add
py_sql/ html_sql
functions.see - rbatis/example
- abs_admin project an complete background user management system( Vue.js+rbatis+actix-web)
- Thanks to
SQLX, mobc, Tiberius, MyBatis,xorm
and so on reference design or code implementation. release of V4.0 is Inspired and supported by these frameworks
- this bench test is MockTable,MockDriver,MockConnection to Assume that the network I/O time is 0
- run code
MockTable::insert(&mut rbatis.clone(),&t).await;
on benches/fn bench_insert() - use
command
cargo test --release --package rbatis --bench raw_performance bench_insert --no-fail-fast -- --exact -Z unstable-options --show-output
//---- bench_insert stdout ----(win10,cpu-amd5950x)
// use Time: 130.5443ms ,each:1305 ns/op
// use QPS: 765860 QPS/s
//---- bench_insert stdout ----(macos,cpu-M1Max)
//use Time: 128.635666ms ,each:1286 ns/op
//use QPS: 777351 QPS/s
data structure | is supported |
---|---|
Option | √ |
Vec | √ |
HashMap | √ |
i32,i64,f32,f64,bool,String...more rust type | √ |
rbatis::rbdc::types::{Date,FastDateTime,Time,Timestamp,Decimal,Json} | √ |
rbatis::plugin::page::{Page, PageRequest} | √ |
rbs::Value* | √ |
serde_json::* | √ |
any serde type | √ |
driver type on package (rdbc-mysql/types,rbdc-pg/types,rbdc-sqlite/types) | √ |
database | crates.io | github_link |
---|---|---|
Mysql | rbdc-mysql | rbatis |
Postgres | rbdc-pg | rbatis |
Sqlite | rbdc-sqlite | rbatis |
Mssql | rbdc-mssql | rbatis |
MariaDB | rbdc-mysql | rbatis |
TiDB | rbdc-mysql | rbatis |
CockroachDB | rbdc-pg | rbatis |
Oracle | rbdc-oracle | chenpengfan |
Supported OS/Platforms by Workflows CI
platform | is supported |
---|---|
Linux(unbutu laster***) | √ |
Apple/MacOS(laster) | √ |
Windows(latest) | √ |
- any web Frameworks just like actix-web,axum,hyper*,rocket,tide,warp,salvo...... and more
- Cargo.toml
# logging(option)
log = "0.4"
fast_log = "1.5"
# serde/rbs (required)
serde = { version = "1", features = ["derive"] }
rbs = { version = "0.1"}
rbatis = { version = "4.0"}
# choose one rbdc drivier
rbdc-sqlite = { version = "0.1" }
#rbdc-mysql={version="0.1"}
#rbdc-pg={version="0.1"}
#rbdc-mssql={version="0.1"}
#...other database driver...
//#[macro_use] define in 'root crate' or 'mod.rs' or 'main.rs'
#[macro_use]
extern crate rbatis;
extern crate rbdc;
use rbatis::{impl_insert, impl_insert, impl_update, impl_delete, impl_select_page};
use rbatis::rbdc::datetime::FastDateTime;
#[derive(Clone, Debug, Serialize, Deserialize)]
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<FastDateTime>,
pub version: Option<i64>,
pub delete_flag: Option<i32>,
}
crud!(BizActivity{});//crud = insert+select_by_column+update_by_column+delete_by_column
impl_select!(BizActivity{select_all_by_id(id:&str,name:&str) => "`where id = #{id} and name = #{name}`"});
impl_select!(BizActivity{select_by_id(id:String) -> Option => "`where id = #{id} limit 1`"});
impl_update!(BizActivity{update_by_name(name:&str) => "`where id = 1`"});
impl_delete!(BizActivity {delete_by_name(name:&str) => "`where name= '2'`"});
impl_select_page!(BizActivity{select_page(name:&str) => "`where name != #{name}`"});
#[tokio::main]
async fn main() {
/// enable log crate to show sql logs
fast_log::init(fast_log::Config::new().console()).expect("rbatis init fail");
/// initialize rbatis. also you can call rb.clone(). this is an Arc point
let rb = Rbatis::new();
/// connect to database
// sqlite
rb.link(SqliteDriver {}, "sqlite://target/sqlite.db").await.unwrap();
// mysql
// rb.link(MysqlDriver{},"mysql://root:123456@localhost:3306/test").await.unwrap();
// postgresql
// rb.link(PgDriver{},"postgres://postgres:123456@localhost:5432/postgres").await.unwrap();
// mssql/sqlserver
// rb.link(MssqlDriver{},"jdbc:sqlserver://localhost:1433;User=SA;Password={TestPass!123456};Database=test").await.unwrap();
let activity = BizActivity {
id: Some("2".into()),
name: Some("2".into()),
pc_link: Some("2".into()),
h5_link: Some("2".into()),
pc_banner_img: None,
h5_banner_img: None,
sort: None,
status: Some(2),
remark: Some("2".into()),
create_time: Some(FastDateTime::now()),
version: Some(1),
delete_flag: Some(1),
};
let data = BizActivity::insert(&mut rb, &activity).await;
println!("insert = {:?}", data);
let data = BizActivity::select_all_by_id(&mut rb, "1", "1").await;
println!("select_all_by_id = {:?}", data);
let data = BizActivity::select_by_id(&mut rb, "1".to_string()).await;
println!("select_by_id = {:?}", data);
let data = BizActivity::update_by_column(&mut rb, &activity, "id").await;
println!("update_by_column = {:?}", data);
let data = BizActivity::update_by_name(&mut rb, &activity, "test").await;
println!("update_by_name = {:?}", data);
let data = BizActivity::delete_by_column(&mut rb, "id", &"2".into()).await;
println!("delete_by_column = {:?}", data);
let data = BizActivity::delete_by_name(&mut rb, "2").await;
println!("delete_by_column = {:?}", data);
let data = BizActivity::select_page(&mut rb, &PageRequest::new(1, 10), "2").await;
println!("select_page = {:?}", data);
}
///...more usage,see crud.rs
- 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("select * from biz_activity where delete_flag = 0
if name != '':
`and name=#{name}`")]
async fn py_sql_tx(rb: &Rbatis, tx_id: &String, name: &str) -> Vec<BizActivity> { impled!() }
- 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://raw.githubusercontent.com/rbatis/rbatis/master/rbatis-codegen/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("example/example.html")]
async fn select_by_condition(rb: &mut dyn Executor, page_req: &PageRequest, name: &str) -> Page<BizActivity> { impled!() }
use once_cell::sync::Lazy;
pub static RB: Lazy<Rbatis> = Lazy::new(|| Rbatis::new());
/// Macro generates execution logic based on method definition, similar to @select dynamic SQL of Java/Mybatis
/// RB is the name referenced locally by Rbatis, for example DAO ::RB, com:: XXX ::RB... Can be
/// The second parameter is the standard driver SQL. Note that the corresponding database parameter mysql is? , pg is $1...
/// macro auto edit method to 'pub async fn select(name: &str) -> rbatis::core::Result<BizActivity> {}'
///
#[sql("select * from biz_activity where id = ?")]
pub async fn select(rb: &Rbatis, name: &str) -> BizActivity {}
//or: pub async fn select(name: &str) -> rbatis::core::Result<BizActivity> {}
#[tokio::test]
pub async fn test_macro() {
fast_log::init(fast_log::Config::new().console()).expect("rbatis init fail");
RB.link("mysql://root:123456@localhost:3306/test").await.unwrap();
let a = select(&RB, "1").await.unwrap();
println!("{:?}", a);
}
- sqlite table sync plugin(auto create table/column)
- Static analysis and generate executable test functions
Contact/donation, or click on star rbatis
联系方式/捐赠,或 rbatis 点star
捐赠
联系方式(添加好友请备注'rbatis') 微信群:先加微信,然后拉进群