use lazy_static::lazy_static;
use anyhow::Context as _;
use serde::{Deserialize, Serialize};
use sqlx::mysql::MySqlRow;
use sqlx::{MySql, Pool, QueryBuilder, Row};
lazy_static! {
#[rustfmt::skip]
pub static ref SELECT_STATMENT: &'static str = "select f_id, f_user_id, f_app, f_name, f_digits, f_issuer, f_period, f_expired_at, f_key, f_code, f_created_at, f_updated_at from t_otp_code";
}
use crate::core::error2::Result;
#[rustfmt::skip]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct OtpCodeRecord {
pub id: u64,
#[serde(skip_serializing_if = "String::is_empty")]
pub user_id: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub app: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub name: String,
pub digits: u32,
#[serde(skip_serializing_if = "String::is_empty")]
pub issuer: String,
pub period: u32,
pub expired_at: u64,
#[serde(skip_serializing_if = "String::is_empty")]
pub key: String,
pub code: u32,
pub created_at: u64,
pub updated_at: u64,
}
#[rustfmt::skip]
#[allow(dead_code)]
impl OtpCodeRecord {
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub async fn select_by_primary_key(pool: &Pool<MySql>, id: &u64) -> Result<Option<MySqlRow>> {
#[rustfmt::skip]
let statment: &str = *SELECT_STATMENT;
let mut query_builder: sqlx::QueryBuilder<sqlx::MySql> = sqlx::QueryBuilder::new(statment);
query_builder.push(" where f_id = ");
query_builder.push_bind(id);
let row = query_builder
.build()
.fetch_optional(pool)
.await
.context("select_by_primary_key: Failed to perform a query to retrieve a otpcode.")?;
Ok(row)
}
pub async fn insert(pool: &Pool<MySql>, record: &OtpCodeRecord) -> Result<u64> {
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
"INSERT INTO t_otp_code (f_user_id, f_app, f_name, f_digits, f_issuer, f_period, f_expired_at, f_key, f_code, f_created_at, f_updated_at) ",
);
query_builder.push_values([record].iter(), |mut b, record| {
b.push_bind(record.user_id.to_owned());
b.push_bind(record.app.to_owned());
b.push_bind(record.name.to_owned());
b.push_bind(record.digits.to_owned());
b.push_bind(record.issuer.to_owned());
b.push_bind(record.period.to_owned());
b.push_bind(record.expired_at.to_owned());
b.push_bind(record.key.to_owned());
b.push_bind(record.code.to_owned());
b.push_bind(record.created_at.to_owned());
b.push_bind(record.updated_at.to_owned());
});
let mut transaction = pool.begin().await.map_err(|e| {
log::error!("insert-failed: error={:?}", e);
anyhow::anyhow!(e)
})?;
let last_insert_id = query_builder
.build()
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!(e))?
.last_insert_id();
transaction.commit().await.map_err(|e| {
log::error!("insert-failed: error={:?}", e);
anyhow::anyhow!(e)
})?;
Ok(last_insert_id)
}
pub async fn insert_bulk(pool: &Pool<MySql>, data: Vec<OtpCodeRecord>) -> Result<u64> {
let mut insert_result_int = 0;
for chunk in data.chunks(5000) {
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
"INSERT INTO t_otp_code (f_user_id, f_app, f_name, f_digits, f_issuer, f_period, f_expired_at, f_key, f_code, f_created_at, f_updated_at) ",
);
query_builder.push_values(chunk.iter().take(5000 / 12), |mut b, record| {
b.push_bind(record.user_id.to_owned());
b.push_bind(record.app.to_owned());
b.push_bind(record.name.to_owned());
b.push_bind(record.digits.to_owned());
b.push_bind(record.issuer.to_owned());
b.push_bind(record.period.to_owned());
b.push_bind(record.expired_at.to_owned());
b.push_bind(record.key.to_owned());
b.push_bind(record.code.to_owned());
b.push_bind(record.created_at.to_owned());
b.push_bind(record.updated_at.to_owned());
});
insert_result_int += query_builder
.build()
.execute(pool)
.await
.map_err(|e| anyhow::anyhow!(e))?
.rows_affected();
}
Ok(insert_result_int)
}
pub async fn update_by_primary_key(
pool: &Pool<MySql>,
id: &i64,
data: &OtpCodeRecord,
) -> Result<bool> {
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new("update t_otp_code ");
query_builder.push("set f_user_id = ");
query_builder.push_bind(data.user_id.trim());
query_builder.push(", f_app = ");
query_builder.push_bind(data.app.trim());
query_builder.push(", f_name = ");
query_builder.push_bind(data.name.trim());
query_builder.push(", f_digits = ");
query_builder.push_bind(data.digits);
query_builder.push(", f_issuer = ");
query_builder.push_bind(data.issuer.trim());
query_builder.push(", f_period = ");
query_builder.push_bind(data.period);
query_builder.push(", f_expired_at = ");
query_builder.push_bind(data.expired_at);
query_builder.push(", f_key = ");
query_builder.push_bind(data.key.trim());
query_builder.push(", f_code = ");
query_builder.push_bind(data.code);
query_builder.push(", f_created_at = ");
query_builder.push_bind(data.created_at);
query_builder.push(", f_updated_at = ");
query_builder.push_bind(data.updated_at);
query_builder.push(" where f_id = ");
query_builder.push_bind(id);
let update_result_int = query_builder
.build()
.execute(pool)
.await
.map_err(|e| anyhow::anyhow!(e))?
.rows_affected();
Ok(update_result_int > 0)
}
pub async fn update_by_primary_key_selective(
pool: &Pool<MySql>,
id: &i64,
data: &OtpCodeRecord,
) -> Result<bool> {
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new("update t_otp_code");
query_builder.push("set f_user_id = ");
query_builder.push_bind(data.user_id.trim());
query_builder.push(", f_app = ");
query_builder.push_bind(data.app.trim());
query_builder.push(", f_name = ");
query_builder.push_bind(data.name.trim());
query_builder.push(", f_digits = ");
query_builder.push_bind(data.digits);
query_builder.push(", f_issuer = ");
query_builder.push_bind(data.issuer.trim());
query_builder.push(", f_period = ");
query_builder.push_bind(data.period);
query_builder.push(", f_expired_at = ");
query_builder.push_bind(data.expired_at);
query_builder.push(", f_key = ");
query_builder.push_bind(data.key.trim());
query_builder.push(", f_code = ");
query_builder.push_bind(data.code);
query_builder.push(", f_created_at = ");
query_builder.push_bind(data.created_at);
query_builder.push(", f_updated_at = ");
query_builder.push_bind(data.updated_at);
query_builder.push(" where f_id = ");
query_builder.push_bind(id);
let update_result_int = query_builder
.build()
.execute(pool)
.await
.map_err(|e| anyhow::anyhow!(e))?
.rows_affected();
Ok(update_result_int > 0)
}
pub fn from_row(row: sqlx::mysql::MySqlRow) -> Result<OtpCodeRecord> {
Ok(OtpCodeRecord {
id: row.get(0),
user_id: row.get(1),
app: row.get(2),
name: row.get(3),
digits: row.get(4),
issuer: row.get(5),
period: row.get(6),
expired_at: row.get(7),
key: row.get(8),
code: row.get(9),
created_at: row.get(10),
updated_at: row.get(11),
})
}
}