Releases: rbatis/rbatis
Releases Β· rbatis/rbatis
v4.7.2
what changes?
- remove #[html_sql] for mod
- add Page support for #[html_sql] for struct
for example:
#[rbatis::html_sql("example/example.html")]
impl Activity {
/// Paginated query - automatically detected by return type Page<Activity>
/// Maps to <select id="select_by_page"> in HTML
/// The macro automatically generates pagination logic using PageIntercept
pub async fn select_by_page(
rb: &dyn Executor,
page_req: &dyn PageRequest,
name: &str,
dt: Option<DateTime>,
) -> rbatis::Result<rbatis::Page<Activity>> {
impled!()
}
}<!-- Paginated query - automatically detected by return type Page<Activity> -->
<select id="select_by_page">
`select * from activity`
<where>
<if test="name != ''">
` and name like #{name}`
</if>
<if test="dt != null">
` and create_time < #{dt}`
</if>
</where>
<!-- PageIntercept will add limit/offset automatically -->
</select>v4.7.1
what changes?
- merge #609 for struct/mod html_sql mapping
for example:
use rbatis::dark_std::defer;
use rbatis::executor::Executor;
use rbatis::rbdc::datetime::DateTime;
use rbatis::RBatis;
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct Activity {
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<DateTime>,
pub version: Option<i64>,
pub delete_flag: Option<i32>,
}
/// All methods read SQL from example/example.html
#[rbatis::html_sql("example/example.html")]
impl Activity {
/// Maps to <select id="select_by_condition"> in HTML
pub async fn select_by_condition(
rb: &dyn Executor,
name: &str,
dt: &DateTime,
) -> rbatis::Result<Vec<Activity>> {
impled!()
}
/// Maps to <select id="select_page_data"> in HTML
pub async fn select_page_data(
rb: &dyn Executor,
name: &str,
dt: &DateTime,
) -> rbatis::Result<Vec<Activity>> {
impled!()
}
/// Maps to <update id="update_by_id"> in HTML
pub async fn update_by_id(
rb: &dyn Executor,
arg: &Activity,
) -> rbatis::Result<rbatis::rbdc::db::ExecResult> {
impled!()
}
}<!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 activity`
<where>
<if test="name != ''">
` and name like #{name}`
</if>
<if test="dt >= '2009-12-12 00:00:00'">
` and create_time < #{dt}`
</if>
<choose>
<when test="true">
` and id != '-1'`
</when>
<otherwise>and id != -2</otherwise>
</choose>
` and `
<trim prefixOverrides=" and">
` and name != '' `
</trim>
</where>
</select>
<select id="select_page_data">
`select * from activity `
<where>
<if test="name != ''">
` and name like #{name}`
</if>
<if test="dt >= '2009-12-12 00:00:00'">
` and create_time < #{dt}`
</if>
<choose>
<when test="true">
` and id != '-1'`
</when>
<otherwise>and id != -2</otherwise>
</choose>
` and `
<trim prefixOverrides=" and">
` and name != '' `
</trim>
</where>
</select>
<update id="update_by_id">
` update activity `
<set collection="arg"></set>
` where id = #{id} `
</update>
</mapper>v4.7.0
what changes?
- RBatis Engine All use dyn Trait for example:
pub struct RBatis {
// the connection pool
pub pool: Arc<OnceLock<Box<dyn Pool>>>,
// intercept vec(default the intercepts[0] is a log interceptor)
pub intercepts: Arc<SyncVec<Arc<dyn Intercept>>>,
//rb task id gen
pub task_id_generator: Arc<dyn IdGenerator>,
}- performance
| Optimization Item | Save Time |
|---------------------------------|-----------|
| Avoid `vec![]` allocation | ~50 ns |
| Avoid creating RBAtisKonExecutor| ~100 ns |
| Avoid `task_id` generation | ~11 ns |
| Avoid `Arc` cloning | ~20 ns |
| Reduce function call hierarchy | ~50 ns |
| Empty string fast path | ~30 ns |
| **Total** | **~260 ns** |- intercept add Action
use rbatis::Error;
use rbatis::executor::Executor;
use rbatis::intercept::{Intercept, ResultType};
use rbdc::db::ExecResult;
use rbs::Value;
use rbatis::Action;
#[derive(Debug)]
pub struct ReturningIdPlugin{}
#[rbatis::async_trait]
impl Intercept for ReturningIdPlugin {
async fn before(
&self,
_task_id: i64,
rb: &dyn Executor,
sql: &mut String,
args: &mut Vec<Value>,
result: ResultType<&mut Result<ExecResult, Error>, &mut Result<Value, Error>>,
) -> Result<Action, Error> {
Ok(Action::Next)
}
}v4.6.15
v4.6.14
v4.6.13
what changes?
- Support for temporarily replacing the interceptor list
for example:
/// Mock intercept that just prints SQL
#[derive(Debug)]
pub struct MockIntercept;
#[async_trait]
impl Intercept for MockIntercept {
async fn before(
&self,
task_id: i64,
_rb: &dyn Executor,
sql: &mut String,
_args: &mut Vec<Value>,
_result: ResultType<&mut Result<ExecResult, rbatis::Error>, &mut Result<Vec<Value>, rbatis::Error>>,
) -> Result<Option<bool>, rbatis::Error> {
*sql = sql.replace("<my_table_name>", &format!("activity_{}",task_id % 2));
println!("MockIntercept: SQL = {}", sql);
Ok(Some(true))
}
}
#[tokio::main]
pub async fn main() -> Result<(), rbatis::Error> {
_ = fast_log::init(fast_log::Config::new().console());
let rb = RBatis::new();
rb.init(rbdc_sqlite::driver::SqliteDriver {}, "sqlite://target/sqlite.db")?;
// create table
_=rb.exec("CREATE TABLE activity_0 ( id INTEGER PRIMARY KEY);", vec![]).await;
_=rb.exec("CREATE TABLE activity_1 ( id INTEGER PRIMARY KEY);", vec![]).await;
let len = rb.intercepts.len();
println!("len={}", len);
// Create new intercept list and add our mock intercept
let new_intercept = Arc::new(SyncVec::new());
let intercept: Arc<dyn Intercept> = Arc::new(MockIntercept {});
new_intercept.push(intercept);
// Create connection and replace its intercepts
let mut conn = rb.acquire().await?;
conn.intercepts = new_intercept;
println!("conn.intercepts.len={}", conn.intercepts.len());
// Execute query to see the mock intercept in action
let _ = conn.query("SELECT <my_table_name>", vec![]).await;
let data = Activity::select_all(&conn).await?;
println!("data={:?}", json!(data));
Ok(())
}
/// table
#[derive(serde::Serialize, serde::Deserialize, Clone)]
pub struct Activity {
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<DateTime>,
pub version: Option<i64>,
pub delete_flag: Option<i32>,
}
//crud!(Activity {},"activity");
crud!(Activity {},"<my_table_name>");v4.6.12
what changes?
- impl #591 for
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
struct MockTable {
pub id: Option<String>,
pub name: Option<String>,
pub status: Option<i32>
}
crud!(MockTable{});
let r = MockTable::update_by_map(rb, &table, value!{"id":"1", "column": ["name", "status"]}).await;- impl
crud!for select target columns
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
struct MockTable {
pub id: Option<String>,
pub name: Option<String>,
pub status: Option<i32>
}
crud!(MockTable{});
let tables = MockTable::select_by_map(rb,value!{"id":"1", "column": ["id", "name"]}).await?; v4.6.9
v4.6.8
add page method:
/// create Vec<PageRequest> from (total: u64, page_size: u64)
pub fn make_page_requests(total: u64, page_size: u64) -> Vec<PageRequest> {
let mut result = vec![];
let pages = PageRequest::new(1, page_size).set_total(total).pages();
for idx in 0..pages {
let current_page = PageRequest::new(idx + 1, page_size).set_total(total);
result.push(current_page);
}
result
}