Rust simplified version of MybatisPlus - let you switch from Java to rust in one day

Posted by pacholo on Sun, 19 Dec 2021 22:43:12 +0100

In short, it has been almost a year since the real start of project development with Rust, and they are becoming more and more popular with Rust; In this process, I stepped on many pits, and had to make up a lot of abandoned knowledge due to Rust's metamorphosis; Of course, I have a deeper understanding of computers, and my hair naturally becomes thinner and thinner.

”Circle gauge

Today, I'd like to share with you one of my own Crites. In recent years, more and more small partners have transferred to Rust. Many of them are transferred from Java posts. The first thing they do is frantically looking for a useful ORM framework. However, the relevant database frameworks in Rust are diesel, sqlx, etc., which can basically meet the daily work needs. In order to facilitate the transition of more small partners to Rust, we have created a small framework. With reference to the relevant API s of MyBatisPlus, we believe that small partners who have used the framework should be able to transition seamlessly. It has now transitioned to 0.2 Version 0 is basically updated frequently, because there are many ideas in the early stage and there is no fixed direction, so it is often overturned and restarted.

This crab is called akita, which translates to the meaning of akita dog, and also represents the meaning of cute and cute. The basic implementation idea is to complete the mapping of database table structure through Rust's process macro, and then encapsulate some convenient SQL assembly tools and methods. At present, the project only supports MySQL, and the thread pool used is r2d2. It is planned to support ClickHouse, SQLite, MSSQL, ORACLE and other databases.

Direct code opening

If you don't say much, let's code directly. Can you use it? Let's try one. First, add dependencies. The current version is 0.2.0 4.

[dependencies]

# The core APIs, including the Table traits. Always
# required when using Akita. using #[derive(Table)] 
# to make Akita work with structs defined in your crate.
akita = { version = "0.2.0"] }

First, we define a structure SystemUser. Akita provides three trait s, namely FromAkita, ToAkita and table, which are mainly used to parse the field structure of the structure and generate basic CRUD member methods. In addition, the table annotation is provided to mark the database table name, field and table_ The ID labels the column name and the primary key, and each has a name attribute, while retaining the exist attribute in MyBatisPlus.

#[derive(Debug, FromAkita, ToAkita, Table, Clone)]
#[table(name="t_system_user")]
struct SystemUser {
    #[field = "name"]
    id: Option<i32>,
    #[table_id]
    username: String,
    #[field(name="ages", exist = "false")]
    age: i32,
}


Come on, Akita provides two public managers, AkitaManager and AkitaEntityManager. The former mainly encapsulates some original SQL operations, while the latter adds more complete APIs and implements these APIs in the structure. We take CRUD operation as an example:

use akita::*;
use akita::prelude::*;

fn main() {
    let mut pool = Pool::new(AkitaConfig{ max_size: None, url: String::from("mysql://root:password@localhost:3306/akita"), log_level: None }).unwrap();
    let mut em = pool.entity_manager().expect("must be ok");
    let user = SystemUser { id: 1.into(), username: "fff".to_string(), age: 1 };

    // newly added
    match em.save(&user) {
        Ok(res) => { }
        Err(err) => { }
    }
    ///Structure example
    match user.insert(&mut em) {
        Ok(res) => { }
        Err(err) => { }
    }

    // delete
    match em.remove_by_id::<SystemUser, String>("id".to_string()) {
        Ok(res) => { }
        Err(err) => { }
    }

    // modify
    match em.update_by_id(&user, "id") {
        Ok(res) => { }
        Err(err) => { }
    }

    // Query paging
    let mut wrapper = UpdateWrapper::new();
    wrapper.eq( "username", "ussd").eq("id", 1);
    match em.page::<SystemUser, UpdateWrapper>(1, 10,&mut wrapper) {
        Ok(res) => { }
        Err(err) => { }
    }
    // Query single
    match em.select_one::<SystemUser, UpdateWrapper>(&mut wrapper) {
        Ok(res) => { }
        Err(err) => { }
    }

    ...
}

Are you very moved after reading it? It's a blessing for me who has written SQL for more than half a year... In addition, there are many performance aspects that we are optimizing, such as paging of large amount of data, interception of related slow SQL and some other optimizations.

plan

At present, only a few people maintain the project, so the update speed will not be fast in the future. We will also use this framework in production and gradually optimize it. What we plan to do in the future:

  • Multiple feature s such as ORACLE, ClickHouse, SQLite and MSSQL are supported
  • Strengthen annotations, add configuration mapping, and support more customized annotations
  • Support more data structures and optimize internal parameter processing
  • Improve the automatic code generation tool to reduce repetitive work

Run after the yard (lazy)

So it's your time to copy and slip. (escape)

Topics: Java Database MySQL Rust orm