Expand description
§Rbatis
§📖 English Documentation | 📖 中文文档
§Introduction
Rbatis is a high-performance ORM framework for Rust based on compile-time code generation. It perfectly balances development efficiency, performance, and stability, functioning as both an ORM and a dynamic SQL compiler.
§More Supported
- Full Documentation
- Changelog
- rbdc-mcp AI driver for database access
- rbatis-skil AI driver for ORM useage
§Core Advantages
§1. High Performance
- 🚀 Dynamic SQL to Native Rust Translation: The key advantage - compiles dynamic SQL directly to native Rust code, achieving performance equivalent to hand-written SQL
- Zero Runtime Overhead: All SQL parsing and optimization happens at compile-time, eliminating runtime interpretation costs
- Based on Tokio Async Model: Fully utilizes Rust’s async features to enhance concurrency performance
- Efficient Connection Pools: Built-in multiple connection pool implementations, optimizing database connection management
§2. Reliability
- Rust Safety Features: Leverages Rust’s ownership and borrowing checks to ensure memory and thread safety
- Unified Parameter Placeholders: Uses
?as a unified placeholder, supporting all drivers - Two Replacement Modes: Precompiled
#{arg}and direct replacement${arg}, meeting different scenario requirements
§3. Development Efficiency
- Powerful ORM Capabilities: Automatic mapping between database tables and Rust structures
- Multiple SQL Building Methods:
- py_sql: Python-style dynamic SQL with
if,for,choose/when/otherwise,bind,trimstructures and collection operations (.sql(),.csv()) - html_sql: MyBatis-like XML templates with familiar tag structure (
<if>,<where>,<set>,<foreach>), declarative SQL building, and automatic handling of SQL fragments without requiring CDATA - Raw SQL: Direct SQL statements
- py_sql: Python-style dynamic SQL with
- CRUD Macros: Generate common CRUD operations with a single line of code
- Interceptor Plugin: Custom extension functionality
- Table Sync Plugin: Automatically create/update table structures
§4. Extensibility
- Multiple Database Support: MySQL, PostgreSQL, SQLite, MSSQL, MariaDB, TiDB, CockroachDB, Oracle, TDengine, etc.
- Custom Driver Interface: Implement a simple interface to add support for new databases
- Multiple Connection Pools: FastPool (default), Deadpool, MobcPool
- Compatible with Various Web Frameworks: Seamlessly integrates with ntex, actix-web, axum, hyper, rocket, tide, warp, salvo, and more
§Supported Database Drivers
§Supported Connection Pools
| Connection Pool (crates.io) | GitHub Link |
|---|---|
| FastPool (default) | rbatis/fast_pool |
| Deadpool | rbatis/rbdc-pool-deadpool |
| MobcPool | rbatis/rbdc-pool-mobc |
§Supported Data Types
| Data Type | Support |
|---|---|
Option | ✓ |
Vec | ✓ |
HashMap | ✓ |
i32, i64, f32, f64, bool, String, and other Rust base types | ✓ |
rbatis::rbdc::types::{Bytes, Date, DateTime, Time, Timestamp, Decimal, Json} | ✓ |
rbatis::plugin::page::{Page, PageRequest} | ✓ |
rbs::Value | ✓ |
serde_json::Value and other serde types | ✓ |
| Driver-specific types from rbdc-mysql, rbdc-pg, rbdc-sqlite, rbdc-mssql | ✓ |
§Member crates
§How Rbatis Works
Rbatis uses compile-time code generation through the rbatis-codegen crate, which means:
-
🎯 Direct Translation to Native Rust: Dynamic SQL is converted to optimized Rust code during compilation, achieving performance identical to hand-written SQL without any runtime interpretation overhead.
-
Compilation Process:
- Lexical Analysis: Handled by
func.rsinrbatis-codegenusing Rust’ssynandquotecrates - Syntax Parsing: Performed by
parser_htmlandparser_pysqlmodules inrbatis-codegen - Abstract Syntax Tree: Built using structures defined in the
syntax_treepackage inrbatis-codegen - Intermediate Code Generation: Executed by
func.rs, which contains all the code generation functions
- Lexical Analysis: Handled by
-
Build Process Integration: The entire process runs during the
cargo buildphase as part of Rust’s procedural macro compilation. The generated code is returned to the Rust compiler for LLVM compilation to produce machine code. -
Compile-Time SQL Optimization: Unlike traditional ORMs that interpret dynamic SQL at runtime (causing performance penalties), Rbatis translates SQL to native Rust code at compile-time, delivering hand-written SQL performance while maintaining ORM convenience.
§Performance Benchmarks
---- bench_raw stdout ----(windows/SingleThread)
Time: 52.4187ms ,each:524 ns/op
QPS: 1906435 QPS/s
---- bench_select stdout ----(macos-M1Cpu/SingleThread)
Time: 112.927916ms ,each:1129 ns/op
QPS: 885486 QPS/s
---- bench_insert stdout ----(macos-M1Cpu/SingleThread)
Time: 346.576666ms ,each:3465 ns/op
QPS: 288531 QPS/s§Quick Start
§Dependencies
# Cargo.toml
[dependencies]
#drivers
rbdc-sqlite = { version = "4" }
# rbdc-mysql = { version = "4" }
# rbdc-pg = { version = "4" }
# rbdc-mssql = { version = "4" }
rbs = { version = "4"}
rbatis = { version = "4.8"}
# Other dependencies
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
log = "0.4"
fast_log = "1.6"§Basic Usage
use rbatis::rbdc::datetime::DateTime;
use rbs::value;
use rbatis::crud;
use rbatis::RBatis;
use rbdc_sqlite::SqliteDriver;
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Activity {
pub id: Option<String>,
pub name: Option<String>,
pub create_time: Option<DateTime>
}
// Automatically generate CRUD methods
crud!(Activity{});
#[tokio::main]
async fn main() {
// Configure logging (optional, any logger works)
// fast_log::init(fast_log::Config::new().console()).expect("log init fail");
// Initialize rbatis
let rb = RBatis::new();
// Connect to database
rb.init(SqliteDriver {}, "sqlite://target/sqlite.db").expect("rb init fail");
// /// other databases
// rb.init(PgDriver{}, "postgres://postgres:123456@localhost:5432/postgres").expect("pool init fail");
// rb.init(MysqlDriver{}, "mysql://root:123456@localhost:3306/test").expect("pool init fail");
// Create data
let activity = Activity {
id: Some("1".into()),
name: Some("Test Activity".into()),
create_time: Some(DateTime::now()),
};
let arrays = vec![
Activity {
id: Some("2".into()),
name: Some("Activity 2".into()),
create_time: Some(DateTime::now())
},
Activity {
id: Some("3".into()),
name: Some("Activity 3".into()),
create_time: Some(DateTime::now())
},
];
// Insert data
let data = Activity::insert(&rb, &activity).await;
// Batch insert
let data = Activity::insert_batch(&rb, &arrays, 10).await;
// Update by map condition (updates all fields)
let data = Activity::update_by_map(&rb, &activity, value!{ "id": "1" }).await;
// Update only specific columns using the "column" key in condition (GitHub issue #591)
let data = Activity::update_by_map(&rb, &activity, value!{ "id": "1", "column": ["name", "status"] }).await;
// Query by map condition
let data = Activity::select_by_map(&rb, value!{"id":"2","name":"Activity 2"}).await;
// LIKE query
let data = Activity::select_by_map(&rb, value!{"name like ":"%Activity%"}).await;
// Greater than query
let data = Activity::select_by_map(&rb, value!{"id > ":"2"}).await;
// IN query
let data = Activity::select_by_map(&rb, value!{"id": &["1", "2", "3"]}).await;
// Delete by map condition
let data = Activity::delete_by_map(&rb, value!{"id": &["1", "2", "3"]}).await;
}§Advanced Usage (html_sql)
Use #[rbatis::html_sql("html/file_path")] macro for complex queries like pagination, join queries, etc.:
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct Activity {
pub id: Option<String>,
pub name: Option<String>
}
#[rbatis::html_sql("example/example.html")]
impl Activity {
// Paginated query (PageIntercept handles limit/offset automatically)
pub async fn select_by_page(rb: &dyn rbatis::Executor, page_req: &rbatis::PageRequest, name: &str) -> rbatis::Result<rbatis::Page<Activity>> {impled!()}
pub async fn select_by_condition(rb: &dyn rbatis::Executor,name: &str) -> rbatis::Result<Vec<Activity>> {impled!()}
pub async fn update_by_id(rb: &dyn rbatis::Executor,arg: &Activity) -> rbatis::Result<rbatis::rbdc::ExecResult> {impled!()}
pub async fn delete_by_id(rb: &dyn rbatis::Executor,id: &str) -> rbatis::Result<rbatis::rbdc::ExecResult> {impled!()}
}Corresponding HTML template file example/example.html:
<!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_page">
SELECT * FROM activity
<where>
<if test="name != ''">
AND name LIKE #{name}
</if>
</where>
</select>
<select id="select_by_condition">
SELECT * FROM activity
<where>
<if test="name != ''">
AND name LIKE #{name}
</if>
</where>
</select>
<update id="update_by_id">
` update activity `
<set collection="arg"></set>
` where id = #{id} `
</update>
<delete id="delete_by_id">
DELETE FROM activity WHERE id = #{id}
</delete>
</mapper>Applicable scenarios: paginated queries, join queries, complex dynamic SQL, multi-condition search
§Creating a Custom Database Driver
To implement a custom database driver for Rbatis:
- Define your driver project with dependencies:
[features]
default = ["tls-rustls"]
tls-rustls=["rbdc/tls-rustls"]
tls-native-tls=["rbdc/tls-native-tls"]
[dependencies]
rbs = { version = "4"}
rbdc = { version = "4", default-features = false, optional = true }
fastdate = { version = "0.3" }
tokio = { version = "1", features = ["full"] }- Implement the required traits:
use rbdc::db::{Driver, MetaData, Row, Connection, ConnectOptions, Placeholder};
pub struct YourDriver{}
impl Driver for YourDriver{}
pub struct YourMetaData{}
impl MetaData for YourMetaData{}
pub struct YourRow{}
impl Row for YourRow{}
pub struct YourConnection{}
impl Connection for YourConnection{}
pub struct YourConnectOptions{}
impl ConnectOptions for YourConnectOptions{}
pub struct YourPlaceholder{}
impl Placeholder for YourPlaceholder{}
// Then use your driver:
#[tokio::main]
async fn main() -> Result<(), rbatis::Error> {
let rb = rbatis::RBatis::new();
rb.init(YourDatabaseDriver {}, "database://username:password@host:port/dbname")?;
}§Contact Us
§Donations or Contact
WeChat (Please note ‘rbatis’ when adding as friend)
§API guide
The pages below are the entry points for the runtime API. Most users only need
RBatis (the engine) plus the crud! macro.
| Module | What you find there |
|---|---|
rbatis | RBatis: create the engine, init/link a driver, acquire connections and transactions |
executor | Executor and RBatisRef: every handle that can run SQL (RBatis, RBatisConnExecutor, RBatisTxExecutor, RBatisTxExecutorGuard) |
crud | the crud! macro, which generates insert, insert_batch, select_by_map, update_by_map, delete_by_map for a struct |
crud_traits | small traits used by the generated CRUD code |
plugin | pagination (plugin::page), SQL interceptors (plugin::intercept), distributed ID generators (plugin::id_generator) and table sync (plugin::table_sync) |
decode | decode rbs::Value rows into your own serde types (decode(), decode_ref()) |
error | Error and Result used by every API of this crate |
utils | helper macros: field_name!, field_key!, table!, table_field_vec!, table_field_map!, table_field_set!, table_field_btree! |
Attribute macros live in this crate root as well: py_sql, html_sql and
sql turn a function body into an executable SQL statement at compile time,
impled! is the placeholder body used together with them.
§Feature flags
| Feature | Default | Effect |
|---|---|---|
default | yes | enables the procedural macro driver, so #[py_sql], #[html_sql], #[sql], crud!, table! … are available |
debug_mode | no | prints the JSON rows returned by the database and the generated dynamic SQL code to the log/fast_log output. They are printed with the debug log level, so a logger must be initialized with LevelFilter::Debug |
println_gen | no | prints the Rust code generated by #[py_sql]/#[html_sql] at compile time (useful when debugging a query) |
upper_case_sql_keyword | no | reserved; currently a no-op |
§Documentation
- Full guide / book - the long form documentation, written in Mybatis-3 style
- Chinese documentation
- Examples - one runnable example per feature
- Changelog
Re-exports§
pub extern crate dark_std;pub extern crate rbatis_codegen;pub extern crate rbdc;
Re-exports§
Modules§
- crud
- The
crud!macro, which generates the standard CRUD methods for a table struct. Thecrud!macro and the pagination helpers built on top ofpy_sql/html_sql. - crud_
traits - Traits used by the code generated from
crud!. - decode
- Types and traits for decoding values from the database. Decoding rows into your own types.
- error
ErrorandResult. The error type used by every rbatis API.- executor
- Traits describing anything that can execute SQL:
ExecutorandRBatisRef. Everything that can run SQL. - plugin
- Plugins shipped with rbatis: pagination, SQL interceptors, table sync and ID generators.
- rbatis
- The rbatis engine (
RBatis) and its connection/transaction types. - utils
- Helper macros used by the generated code (
field_name!,table!,impled!, …). Helper macros, mostly used by the code generated fromcrud!and the SQL attribute macros.
Macros§
- crud
- PySql: gen insert/insert_batch, select_by_map, update_by_map, delete_by_map methods
- field_
key - Used to simulate enumerations to improve code maintainability. this is return &str data for example:
- field_
name - Used to simulate enumerations to improve code maintainability. this is return &str data for example:
- htmlsql
- Declare a function whose body is filled in by the
#[html_sql]attribute macro. - htmlsql_
select_ page - Generate a paginated function from an
html_sqltemplate. - impled
- Placeholder body for functions handled by
#[py_sql],#[html_sql]or#[sql]. - pysql
- Declare a function whose body is filled in by the
#[py_sql]attribute macro. - pysql_
select_ page - Generate a paginated function from a
py_sqltemplate. - raw_sql
- Declare a function whose body is filled in by the
#[sql]attribute macro. - table
- Simplifies table construction by relying on the Default trait
- table_
field_ btree - Gets the BtreeMap collection of member attributes of the target Vec for example:
- table_
field_ map - Gets the HashMap collection of member attributes of the target Vec for example:
- table_
field_ set - take the target Vec member attribute Vec collection for example:
- table_
field_ vec - take the target Vec member attribute Vec collection for example:
Structs§
Attribute Macros§
- async_
trait - html_
sql - html sql create macro,this macro use RB.py_query and RB.py_exec for example:
- py_sql
- py sql create macro,this macro use RB.py_query and RB.py_exec
- snake_
name - turn a function declaration into a function that returns the
snake_casename of the type given as the first argument: - sql
- auto create sql macro,this macro use RB.query_prepare and RB.exec_prepare for example: