rbatis
rbatis
Rust

Compile Time Async Dynamic SQL ORM

Last updated Jul 7, 2026
2.5k
Stars
169
Forks
80
Issues
+1
Stars/day
Attention Score
87
Language breakdown
Rust 99.1%
HTML 0.9%
Batchfile 0.0%
Shell 0.0%
β–Έ Files click to expand
README

Rbatis

πŸ“– English Documentation | πŸ“– δΈ­ζ–‡ζ–‡ζ‘£

Website | Showcase | Examples

Build Status doc.rs unsafe forbidden codecov GitHub release discussions

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

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, trim structures 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

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

| Database (crates.io) | GitHub Link | |----------------------------------------------------|-----------------------------------------------------------------------------------| | MySQL | rbatis/rbdc-mysql | | PostgreSQL | rbatis/rbdc-pg | | SQLite | rbatis/rbdc-sqlite | | MSSQL | rbatis/rbdc-mssql | | Truso | rbatis/rbdc-turso | | DuckDB | rbatis/rbdc-duckdb | | MariaDB | rbatis/rbdc-mysql | | TiDB | rbatis/rbdc-mysql | | CockroachDB | rbatis/rbdc-pg | | Oracle | chenpengfan/rbdc-oracle | | TDengine | tdcare/rbdc-tdengine |

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

| crate | GitHub Link | |---------------------------------------|-------------------------------------------------| | rbdc | rbdc | | rbs | rbs |

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.rs in rbatis-codegen using Rust's syn and quote crates - Syntax Parsing: Performed by parserhtml and parserpysql modules in rbatis-codegen - Abstract Syntax Tree: Built using structures defined in the syntax_tree package in rbatis-codegen - Intermediate Code Generation: Executed by func.rs, which contains all the code generation functions
  • Build Process Integration: The entire process runs during the cargo build phase 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::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 fastlog::init(fastlog::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::updatebymap(&rb, &activity, value!{ "id": "1" }).await;

// Update only specific columns using the "column" key in condition (GitHub issue #591) let data = Activity::updatebymap(&rb, &activity, value!{ "id": "1", "column": ["name", "status"] }).await;

// Query by map condition let data = Activity::selectbymap(&rb, value!{"id":"2","name":"Activity 2"}).await;

// LIKE query let data = Activity::selectbymap(&rb, value!{"name like ":"%Activity%"}).await;

// Greater than query let data = Activity::selectbymap(&rb, value!{"id > ":"2"}).await;

// IN query let data = Activity::selectbymap(&rb, value!{"id": &["1", "2", "3"]}).await;

// Delete by map condition let data = Activity::deletebymap(&rb, value!{"id": &["1", "2", "3"]}).await; }

Advanced Usage (html_sql)

Use #[rbatis::htmlsql("html/filepath")] 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 selectbypage(rb: &dyn rbatis::Executor, page_req: &rbatis::PageRequest, name: &str) -> rbatis::Result<rbatis::Page<Activity>> {impled!()}
    pub async fn selectbycondition(rb: &dyn rbatis::Executor,name: &str) -> rbatis::Result<Vec<Activity>> {impled!()}
    pub async fn updatebyid(rb: &dyn rbatis::Executor,arg: &Activity) -> rbatis::Result<rbatis::rbdc::ExecResult> {impled!()}
    pub async fn deletebyid(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="selectbypage">     SELECT * FROM activity     <where>         <if test="name != ''">             AND name LIKE #{name}         </if>     </where>  </select>  <select id="selectbycondition">     SELECT * FROM activity     <where>         <if test="name != ''">             AND name LIKE #{name}         </if>     </where>  </select>  <update id="updatebyid">          update activity          <set collection="arg"></set>          where id = #{id}   </update>  <delete id="deletebyid">     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

discussions

Donations or Contact

zxj347284221

WeChat (Please note 'rbatis' when adding as friend)

zxj347284221

πŸ”— More in this category

Β© 2026 GitRepoTrend Β· rbatis/rbatis Β· Updated daily from GitHub