I just started learning Rust, and try to implement a function like Django's get_or_create.
Now my implementation looks too verbose[ I hope that rust can be neater. Therefore, how can I implement this function in less verbose way? There is probably a way to shorten nested match constructions below?
use log::warn;
use diesel::prelude::*;
use diesel::result;
use crate::db::{get_connection, PgPool};
use crate::models::{NewUser, User};
pub fn get_or_create_user(pool: &PgPool, email: &str) -> User {
use crate::schema::users;
let new_user = NewUser { email };
let mut conn = get_connection(pool);
let result = diesel::insert_into(users::table)
.values(&new_user)
.get_result(&mut conn);
match result {
Ok(user) => return user,
Err(err) => match err {
result::Error::DatabaseError(err_kind, info) => match err_kind {
result::DatabaseErrorKind::UniqueViolation => {
warn!(
"{:?} is already exists. Info: {:?}. Skipping.",
new_user, info
);
// another query to DB to get existing user by email
let user = user_by_email(pool, new_user.email);
return user;
}
_ => {
panic!("Database error: {:?}", info);
}
},
_ => {
// TODO: decide how to deal with unexpected errors
return User {
id: 0,
email: "".into(),
};
}
},
}
}
pub fn user_by_email(pool: &PgPool, user_email: &str) -> User {
use crate::schema::users::dsl::*;
let mut conn = get_connection(pool);
let user = crate::schema::users::dsl::users
.filter(email.eq(user_email))
.first(&mut conn)
.unwrap();
return user;
}