Rust Rocket 之ORM
rocket已经内置了ORM,如果你不使用diesel,那么其实不需要安装diesel。
rocket内置ORM 参考地址
rocket运行版本是nightly,所以我们需要安装nightly版本,第一次执行该命令会进行下载最新版本nightly
rustup default nightly
或者你已经安装了nightly版本,CMD进入项目根目录运行这个命令,来指定当前项目是nightl版本来运行
rustup override set nightly
Cargo.toml
[package] name = "untitled" version = "0.1.0" authors = ["korykim <www@yinzan.cn>"] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] rocket = "0.4.5" diesel = { version = "1.4.5", features = ["mysql"]} dotenv = "0.15.0" r2d2-diesel = "1.0" r2d2 = "0.8" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" custom_derive ="0.1.7" [dependencies.rocket_contrib] version = "*" default-features = false features = ["json"] # Powerful date and time functionality chrono = { version = "0.4.15", features = ["serde"] } # For connecting with the MySQL database diesel = { version = "1.4.2", features = ["chrono"] }
Rocket.toml
[development] address = "localhost" port = 9000 limits = { forms = 32768 } [production] address = "0.0.0.0" port = 8000 #workers = [number of cpus * 2] keep_alive = 5 log = "critical" #secret_key = [randomly generated at launch] limits = { forms = 32768 }
在项目目录中创建.env文件,diesel通过读取.env内容来获取连接数据库的连接信息。
.env
diesel setup
创建users表 diesel migration generate users,执行命令会在项目目录中生成migrations文档。
在up.sql里添加内容如下
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for users -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `first_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact; SET FOREIGN_KEY_CHECKS = 1;
up.sql
diesel迁移数据库 diesel migration run
可以看到数据表生成成功了!
同时会自动生成schema文件
schema
创建db.rs
use diesel::mysql::MysqlConnection; use r2d2; use r2d2_diesel::ConnectionManager; use rocket::http::Status; use rocket::request::{self, FromRequest}; use rocket::{Outcome, Request, State}; use std::ops::Deref; pub type Pool = r2d2::Pool<ConnectionManager<MysqlConnection>>; pub fn init_pool(db_url: String) -> Pool { let manager = ConnectionManager::<MysqlConnection>::new(db_url); r2d2::Pool::new(manager).expect("db pool failure") } pub struct Conn(pub r2d2::PooledConnection<ConnectionManager<MysqlConnection>>); impl<'a, 'r> FromRequest<'a, 'r> for Conn { type Error = (); fn from_request(request: &'a Request<'r>) -> request::Outcome<Conn, ()> { let pool = request.guard::<State<Pool>>()?; match pool.get() { Ok(conn) => Outcome::Success(Conn(conn)), Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())), } } } impl Deref for Conn { type Target = MysqlConnection; #[inline(always)] fn deref(&self) -> &Self::Target { &self.0 } }
models.rs
use diesel; use diesel::mysql::MysqlConnection; use diesel::prelude::*; use super::schema::users; use super::schema::users::dsl::users as all_users; // this is to get users from the database #[derive(Serialize, Deserialize, Queryable)] pub struct User { pub id: i32, pub username: String, pub password: String, pub first_name: String, } // decode request data #[derive(Deserialize)] pub struct UserData { pub username: String } // this is to insert users to database #[derive(Serialize, Deserialize, Insertable)] #[table_name = "users"] pub struct NewUser { pub username: String, pub password: String, pub first_name: String, } impl User { pub fn get_all_users(conn: &MysqlConnection) -> Vec<User> { all_users .order(users::id.desc()) .load::<User>(conn) .expect("error!") } pub fn insert_user(user: NewUser, conn: &MysqlConnection) -> bool { diesel::insert_into(users::table) .values(&user) .execute(conn) .is_ok() } pub fn get_user_by_username(user: UserData, conn: &MysqlConnection) -> Vec<User> { all_users .filter(users::username.eq(user.username)) .load::<User>(conn) .expect("error!") } pub fn update_by_username(user: String, first_name: String, conn: &MysqlConnection) -> usize { let updated_row = diesel::update(all_users.filter(users::username.eq(user))) .set(users::first_name.eq(first_name)) .execute(conn) .unwrap(); format!("{}", updated_row).parse().unwrap() } pub fn update_all(user: User, conn: &MysqlConnection) -> Vec<User> { diesel::update(all_users.filter(users::id.eq(user.id))) .set(( users::username.eq(user.username), users::password.eq(user.password), users::first_name.eq(user.first_name) )) .execute(conn) .expect("update error!"); all_users .filter(users::id.eq(user.id)) .load::<User>(conn) .expect("find error!") } pub fn delete_by_name(user: String, conn: &MysqlConnection) -> bool { diesel::delete(all_users.filter(users::username.eq(user))) .execute(conn) .is_ok() } }
routes.rs
use super::db::Conn as DbConn; use rocket_contrib::json::Json; use super::models::{User, NewUser}; use serde_json::Value; use crate::models::UserData; #[get("/all")] pub fn get_all(conn: DbConn) -> Json<Value> { Json(json!({ "status": 200, "result": User::get_all_users(&conn), })) } #[get("/delete/<username>")] pub fn delete_user(conn: DbConn, username: String) -> Json<Value> { let status = User::delete_by_name(username, &conn); Json(json!({ "status": 200, "result": status, })) } #[get("/updateName/<username>/<first_name>")] pub fn update_first_name(conn: DbConn, username: String, first_name: String) -> Json<Value> { let code = User::update_by_username(username, first_name, &conn); let message; if code as i32 == 1 { message = String::from("更新成功!") } else { message = String::from("更新失败!") } Json(json!({ "status": 200, "code":code, "message": message, })) } #[post("/updateAll",format="application/json",data="<update_user>")] pub fn updateall(conn: DbConn, update_user: Json<User>)->Json<Value>{ Json(json!({ "status": User::update_all(update_user.into_inner(), &conn), "result": "ok", })) } #[post("/newUser", format = "application/json", data = "<new_user>")] pub fn new_user(conn: DbConn, new_user: Json<NewUser>) -> Json<Value> { Json(json!({ "status": User::insert_user(new_user.into_inner(), &conn), "result": User::get_all_users(&conn).first(), })) } #[post("/getUser", format = "application/json", data = "<user_data>")] pub fn find_user(conn: DbConn, user_data: Json<UserData>) -> Jsonmain.rs
#![feature(plugin, const_fn, decl_macro, proc_macro_hygiene)] #![allow(proc_macro_derive_resolution_fallback, unused_attributes)] #[macro_use] extern crate diesel; extern crate dotenv; extern crate r2d2; extern crate r2d2_diesel; #[macro_use] extern crate rocket; extern crate rocket_contrib; #[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_json; use dotenv::dotenv; use std::env; use routes::*; use std::process::Command; mod db; mod models; mod routes; mod schema; fn rocket() -> rocket::Rocket { dotenv().ok(); let database_url = env::var("DATABASE_URL").expect("set DATABASE_URL"); let pool = db::init_pool(database_url); rocket::ignite() .manage(pool) .mount( "/api/v1/", routes![get_all,new_user,find_user,delete_user,update_first_name,updateall], ) } fn main() { let _output = if cfg!(target_os = "windows") { Command::new("cmd") .args(&["/C", "cd ui && npm start"]) .spawn() .expect("Failed to start UI Application") } else { Command::new("sh") .arg("-c") .arg("cd ui && npm start") .spawn() .expect("Failed to start UI Application") }; rocket().launch(); }添加用户
查询用户
获取全部
更新全部
更新一条