1
0
mirror of https://github.com/actix/examples synced 2025-06-27 09:29:02 +02:00

Add example for Mysql client library (MySql database driver) #622 (#623)

This commit is contained in:
Last Emperor
2023-07-17 19:31:58 +03:00
committed by GitHub
parent 7736cbb7f7
commit 8e736d9ea4
16 changed files with 948 additions and 0 deletions

View File

@ -0,0 +1,418 @@
use crate::BankDetails;
use crate::BankResponseData;
use crate::BranchDetails;
use crate::BranchResponseData;
use crate::CustomerDetails;
use crate::CustomerResponseData;
use crate::ResponseStatus;
use crate::TellerDetails;
use crate::TellerResponseData;
use actix_web::web;
use mysql::prelude::*;
use mysql::*;
const ERROR_MESSAGE: &str = "Error occured during processing, please try again.";
pub fn create_bank(data: &web::Data<Pool>, bank_name: String, _country: String) -> ResponseStatus {
let my_status_code: u8 = 1;
let my_status_description: String = ERROR_MESSAGE.to_string();
let mut response_status = ResponseStatus {
status_code: my_status_code,
status_description: my_status_description,
};
if bank_name.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Bank name is empty!");
return response_status;
}
if _country.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Country is empty!");
return response_status;
}
match data.get_conn().and_then(|mut conn| {
insert_bank_data(&mut conn, bank_name.to_lowercase(), _country.to_lowercase())
}) {
Ok(x) => {
if x > 0 {
response_status.status_code = 0;
response_status.status_description = String::from("Successful");
}
}
Err(e) => println!("Failed to open DB connection. create_bank {:?}", e),
}
response_status
}
pub fn create_branch(
data: &web::Data<Pool>,
branch_name: String,
_location: String,
) -> ResponseStatus {
let my_status_code: u8 = 1;
let my_status_description: String = ERROR_MESSAGE.to_string();
let mut response_status = ResponseStatus {
status_code: my_status_code,
status_description: my_status_description,
};
if branch_name.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Branch name is empty!");
return response_status;
}
if _location.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Location is empty!");
return response_status;
}
match data.get_conn().and_then(|mut conn| {
insert_branch_data(
&mut conn,
branch_name.to_lowercase(),
_location.to_lowercase(),
)
}) {
Ok(x) => {
if x > 0 {
response_status.status_code = 0;
response_status.status_description = String::from("Successful");
}
}
Err(e) => println!("Failed to open DB connection. create_branch {:?}", e),
}
response_status
}
pub fn create_teller(
data: &web::Data<Pool>,
teller_name: String,
branch_name: String,
) -> ResponseStatus {
let my_status_code: u8 = 1;
let my_status_description: String = ERROR_MESSAGE.to_string();
let mut response_status = ResponseStatus {
status_code: my_status_code,
status_description: my_status_description,
};
if teller_name.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Teller name is empty!");
return response_status;
}
if branch_name.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Branch name is empty!");
return response_status;
}
match data.get_conn().and_then(|mut conn| {
insert_teller_data(
&mut conn,
teller_name.to_lowercase(),
branch_name.to_lowercase(),
)
}) {
Ok(x) => {
if x > 0 {
response_status.status_code = 0;
response_status.status_description = String::from("Successful");
}
}
Err(e) => println!("Failed to open DB connection. create_teller {:?}", e),
}
response_status
}
pub fn create_customer(
data: &web::Data<Pool>,
customer_name: String,
branch_name: String,
) -> ResponseStatus {
let my_status_code: u8 = 1;
let my_status_description: String = ERROR_MESSAGE.to_string();
let mut response_status = ResponseStatus {
status_code: my_status_code,
status_description: my_status_description,
};
if customer_name.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Customer name is empty!");
return response_status;
}
if branch_name.replace(" ", "").trim().len() == 0 {
response_status.status_description = String::from("Branch name is empty!");
return response_status;
}
match data.get_conn().and_then(|mut conn| {
insert_customer_data(
&mut conn,
customer_name.to_lowercase(),
branch_name.to_lowercase(),
)
}) {
Ok(x) => {
if x > 0 {
response_status.status_code = 0;
response_status.status_description = String::from("Successful");
}
}
Err(e) => println!("Failed to open DB connection. create_customer {:?}", e),
}
response_status
}
pub fn get_bank_data(data: &web::Data<Pool>) -> BankResponseData {
let mut vec_bank_data = Vec::new();
let mut my_status_code: u8 = 1;
let mut my_status_description: String = String::from("Record not found");
match data
.get_conn()
.and_then(|mut conn| select_bank_details(&mut conn))
{
Ok(s) => {
vec_bank_data = s;
}
Err(e) => println!("Failed to open DB connection. {:?}", e),
}
if vec_bank_data.len() > 0 {
my_status_code = 0;
my_status_description = String::from("Successful");
}
//Assign values to struct variable
let output_data = BankResponseData {
status_code: my_status_code,
status_description: my_status_description,
bank_data: vec_bank_data,
};
output_data
}
pub fn get_branch_data(data: &web::Data<Pool>) -> BranchResponseData {
let mut vec_branch_data = Vec::new();
let mut my_status_code: u8 = 1;
let mut my_status_description: String = String::from("Record not found");
match data
.get_conn()
.and_then(|mut conn| select_branch_details(&mut conn))
{
Ok(s) => {
vec_branch_data = s;
}
Err(e) => println!("Failed to open DB connection. {:?}", e),
}
if vec_branch_data.len() > 0 {
my_status_code = 0;
my_status_description = String::from("Successful");
}
//Assign values to struct variable
let output_data = BranchResponseData {
status_code: my_status_code,
status_description: my_status_description,
branch_data: vec_branch_data,
};
output_data
}
pub fn get_teller_data(data: &web::Data<Pool>) -> TellerResponseData {
let mut vec_teller_data = Vec::new();
let mut my_status_code: u8 = 1;
let mut my_status_description: String = String::from("Record not found");
match data
.get_conn()
.and_then(|mut conn| select_teller_details(&mut conn))
{
Ok(s) => {
vec_teller_data = s;
}
Err(e) => println!("Failed to open DB connection. {:?}", e),
}
if vec_teller_data.len() > 0 {
my_status_code = 0;
my_status_description = String::from("Successful");
}
//Assign values to struct variable
let output_data = TellerResponseData {
status_code: my_status_code,
status_description: my_status_description,
teller_data: vec_teller_data,
};
output_data
}
pub fn get_customer_data(data: &web::Data<Pool>) -> CustomerResponseData {
let mut vec_customer_data = Vec::new();
let mut my_status_code: u8 = 1;
let mut my_status_description: String = String::from("Record not found");
match data
.get_conn()
.and_then(|mut conn| select_customer_details(&mut conn))
{
Ok(s) => {
vec_customer_data = s;
}
Err(e) => println!("Failed to open DB connection. {:?}", e),
}
if vec_customer_data.len() > 0 {
my_status_code = 0;
my_status_description = String::from("Successful");
}
//Assign values to struct variable
let output_data = CustomerResponseData {
status_code: my_status_code,
status_description: my_status_description,
customer_data: vec_customer_data,
};
output_data
}
fn insert_bank_data(
conn: &mut PooledConn,
my_bank_name: String,
my_country: String,
) -> std::result::Result<u64, mysql::error::Error> {
// Insert data into the database table bank_details
conn.exec_drop(
"insert into bank_details (bank_name, country) values (:bank_name, :country);",
params! {
"bank_name" => my_bank_name,
"country" => my_country,
},
)
.and_then(|_| Ok(conn.last_insert_id()))
}
fn insert_branch_data(
conn: &mut PooledConn,
my_branch_name: String,
my_location: String,
) -> std::result::Result<u64, mysql::error::Error> {
// Insert data into the database table branch_details
conn.exec_drop(
"insert into branch_details (branch_name, location) values (:branch_name, :location);",
params! {
"branch_name" => my_branch_name,
"location" => my_location,
},
)
.and_then(|_| Ok(conn.last_insert_id()))
}
fn insert_teller_data(
conn: &mut PooledConn,
my_teller_name: String,
my_branch_name: String,
) -> std::result::Result<u64, mysql::error::Error> {
// Insert data into the database table teller_details
conn.exec_drop(
"insert into teller_details (teller_name, branch_name) values (:teller_name, :branch_name);",
params! {
"teller_name" => my_teller_name,
"branch_name" => my_branch_name,
},
)
.and_then(|_| Ok(conn.last_insert_id()))
}
fn insert_customer_data(
conn: &mut PooledConn,
my_customer_name: String,
my_branch_name: String,
) -> std::result::Result<u64, mysql::error::Error> {
// Insert data into the database table customer_details
conn.exec_drop(
"insert into customer_details (customer_name, branch_name) values (:customer_name, :branch_name);",
params! {
"customer_name" => my_customer_name,
"branch_name" => my_branch_name,
},
)
.and_then(|_| Ok(conn.last_insert_id()))
}
fn select_bank_details(
conn: &mut PooledConn,
) -> std::result::Result<Vec<BankDetails>, mysql::error::Error> {
let mut bank_data = Vec::new();
conn.query_map(
"select bank_name, country from bank_details where length(trim(coalesce(bank_name,''))) > 0 and length(trim(coalesce(country,''))) > 0 order by id asc;",
|(my_bank_name, my_country)| {
let bank_details = BankDetails { bank_name: my_bank_name, country: my_country, };
bank_data.push(bank_details);
},
)
.and_then(|_| Ok(bank_data))
}
fn select_branch_details(
conn: &mut PooledConn,
) -> std::result::Result<Vec<BranchDetails>, mysql::error::Error> {
let mut branch_data = Vec::new();
conn.query_map(
"select branch_name, location from branch_details where length(trim(coalesce(branch_name,''))) > 0 and length(trim(coalesce(location,''))) > 0 order by id asc;",
|(my_branch_name, my_location)| {
let branch_details = BranchDetails { branch_name: my_branch_name, location: my_location, };
branch_data.push(branch_details);
},
)
.and_then(|_| Ok(branch_data))
}
fn select_teller_details(
conn: &mut PooledConn,
) -> std::result::Result<Vec<TellerDetails>, mysql::error::Error> {
let mut teller_data = Vec::new();
conn.query_map(
"select teller_name, branch_name from teller_details where length(trim(coalesce(teller_name,''))) > 0 and length(trim(coalesce(branch_name,''))) > 0 order by id asc;",
|(my_teller_name, my_branch_name)| {
let teller_details = TellerDetails { teller_name: my_teller_name, branch_name: my_branch_name, };
teller_data.push(teller_details);
},
)
.and_then(|_| Ok(teller_data))
}
fn select_customer_details(
conn: &mut PooledConn,
) -> std::result::Result<Vec<CustomerDetails>, mysql::error::Error> {
let mut customer_data = Vec::new();
conn.query_map(
"select customer_name, branch_name from customer_details where length(trim(coalesce(customer_name,''))) > 0 and length(trim(coalesce(branch_name,''))) > 0 order by id asc;",
|(my_customer_name, my_branch_name)| {
let teller_details = CustomerDetails { customer_name: my_customer_name, branch_name: my_branch_name, };
customer_data.push(teller_details);
},
)
.and_then(|_| Ok(customer_data))
}

246
databases/mysql/src/main.rs Normal file
View File

@ -0,0 +1,246 @@
mod db_layer;
use actix_web::{get, post, web, App, HttpServer, Responder};
use dotenv::dotenv;
use mysql::*;
use serde::{Deserialize, Serialize};
use std::env;
use std::str;
#[derive(Deserialize)]
struct BankData {
bank_name: String,
country: String,
}
#[derive(Deserialize)]
struct BranchData {
branch_name: String,
location: String,
}
#[derive(Deserialize)]
struct TellerData {
teller_name: String,
branch_name: String,
}
#[derive(Deserialize)]
struct CustomerData {
customer_name: String,
branch_name: String,
}
// output
#[derive(Serialize)]
pub struct ResponseStatus {
pub status_code: u8,
pub status_description: String,
}
#[derive(Serialize)]
pub struct BankDetails {
pub bank_name: String,
pub country: String,
}
#[derive(Serialize)]
pub struct BankResponseData {
pub status_code: u8,
pub status_description: String,
pub bank_data: Vec<BankDetails>,
}
#[derive(Serialize)]
pub struct BranchDetails {
pub branch_name: String,
pub location: String,
}
#[derive(Serialize)]
pub struct BranchResponseData {
pub status_code: u8,
pub status_description: String,
pub branch_data: Vec<BranchDetails>,
}
#[derive(Serialize)]
pub struct TellerDetails {
pub teller_name: String,
pub branch_name: String,
}
#[derive(Serialize)]
pub struct TellerResponseData {
pub status_code: u8,
pub status_description: String,
pub teller_data: Vec<TellerDetails>,
}
#[derive(Serialize)]
pub struct CustomerDetails {
pub customer_name: String,
pub branch_name: String,
}
#[derive(Serialize)]
pub struct CustomerResponseData {
pub status_code: u8,
pub status_description: String,
pub customer_data: Vec<CustomerDetails>,
}
#[get("/")]
async fn index() -> impl Responder {
format!("")
}
#[post("/addbank")]
async fn add_bank(bank_data: web::Json<BankData>, data: web::Data<Pool>) -> impl Responder {
let bank_name = &bank_data.bank_name;
let _country = &bank_data.country;
let response_data = db_layer::create_bank(&data, bank_name.to_string(), _country.to_string());
web::Json(response_data)
}
#[post("/addbranch")]
async fn add_branch(branch_data: web::Json<BranchData>, data: web::Data<Pool>) -> impl Responder {
let branch_name = &branch_data.branch_name;
let _location = &branch_data.location;
let response_data =
db_layer::create_branch(&data, branch_name.to_string(), _location.to_string());
web::Json(response_data)
}
#[post("/addteller")]
async fn add_teller(teller_data: web::Json<TellerData>, data: web::Data<Pool>) -> impl Responder {
let teller_name = &teller_data.teller_name;
let branch_name = &teller_data.branch_name;
let response_data =
db_layer::create_teller(&data, teller_name.to_string(), branch_name.to_string());
web::Json(response_data)
}
#[post("/addcustomer")]
async fn add_customer(
customer_data: web::Json<CustomerData>,
data: web::Data<Pool>,
) -> impl Responder {
let customer_name = &customer_data.customer_name;
let branch_name = &customer_data.branch_name;
let response_data =
db_layer::create_customer(&data, customer_name.to_string(), branch_name.to_string());
web::Json(response_data)
}
#[get("/getbank")]
async fn get_bank(data: web::Data<Pool>) -> impl Responder {
let bank_response_data = db_layer::get_bank_data(&data);
web::Json(bank_response_data)
}
#[get("/getbranch")]
async fn get_branch(data: web::Data<Pool>) -> impl Responder {
let branch_response_data = db_layer::get_branch_data(&data);
web::Json(branch_response_data)
}
#[get("/getteller")]
async fn get_teller(data: web::Data<Pool>) -> impl Responder {
let teller_response_data = db_layer::get_teller_data(&data);
web::Json(teller_response_data)
}
#[get("/getcustomer")]
async fn get_customer(data: web::Data<Pool>) -> impl Responder {
let customer_response_data = db_layer::get_customer_data(&data);
web::Json(customer_response_data)
}
fn get_conn_builder(
db_user: String,
db_password: String,
db_host: String,
db_port: u16,
db_name: String,
) -> OptsBuilder {
let builder = OptsBuilder::new()
.ip_or_hostname(Some(db_host))
.tcp_port(db_port)
.db_name(Some(db_name))
.user(Some(db_user))
.pass(Some(db_password));
builder
}
#[actix_web::main]
async fn main() {
// get env vars
dotenv().ok();
let server_addr = env::var("SERVER_ADDR").expect("SERVER_ADDR is not set in .env file");
let db_user = env::var("MYSQL_USER").expect("MYSQL_USER is not set in .env file");
let db_password = env::var("MYSQL_PASSWORD").expect("MYSQL_PASSWORD is not set in .env file");
let db_host = env::var("MYSQL_HOST").expect("MYSQL_HOST is not set in .env file");
let my_db_port = env::var("MYSQL_PORT").expect("MYSQL_PORT is not set in .env file");
let db_name = env::var("MYSQL_DBNAME").expect("MYSQL_DBNAME is not set in .env file");
let mut http_server_status = String::from("[info] ActixWebHttpServer - Listening for HTTP on ");
let db_port: u16 = match my_db_port.parse::<u16>() {
Ok(a) => a,
Err(e) => 0,
};
http_server_status.push_str(&server_addr);
let builder: OptsBuilder = get_conn_builder(db_user, db_password, db_host, db_port, db_name);
let pool = match Pool::new(builder) {
Ok(pool) => pool,
Err(e) => {
println!("Failed to open DB connection. {:?}", e);
return;
}
};
let shared_data = web::Data::new(pool);
let server = match HttpServer::new(move || {
App::new()
.app_data(shared_data.clone())
.service(index)
.service(add_bank)
.service(add_branch)
.service(add_teller)
.service(add_customer)
.service(get_bank)
.service(get_branch)
.service(get_teller)
.service(get_customer)
})
.bind(server_addr)
{
Ok(s) => {
println!("{:?}", http_server_status);
s
}
Err(e) => {
println!("Failed to bind port. {:?}", e);
return;
}
};
match server.run().await {
Ok(_) => println!("Server exited normally."),
Err(e) => println!("Server exited with error: {:?}", e),
};
}