zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use anyhow::Context as _;
use sqlx::mysql::MySqlRow;
use sqlx::{MySql, Pool, QueryBuilder};

use crate::commons::string_to_number;
use crate::{commons::timestamp_millis, core::error2::Result};

use super::models::OtpCodeRecord;

#[derive(serde::Deserialize)]
pub struct OptCodeRenewParam {
    pub id: String,
    pub name: String,
}

impl OtpCodeRecord {
    pub async fn query_by_user_id(
        pool: &Pool<MySql>,
        user_id: &str,
    ) -> Result<Vec<indexmap::IndexMap<String, String>>> {
        #[rustfmt::skip]
        let statment: &str = *super::models::SELECT_STATMENT;

        let mut query_builder: sqlx::QueryBuilder<sqlx::MySql> = sqlx::QueryBuilder::new(statment);

        query_builder.push(" where f_user_id = ");
        query_builder.push_bind(user_id);

        let rows = query_builder
            .build()
            .fetch_all(pool)
            .await
            .context("query_by_user_id: Failed to perform a query to retrieve a otpcode.")?;

        let mut list: Vec<indexmap::IndexMap<String, String>> = Vec::new();

        for row in rows {
            let record = OtpCodeRecord::from_row(row)
                .context("query_by_user_id: Failed to perform from_row.")?;

            let mut result = indexmap::IndexMap::<String, String>::new();

            result.insert("id".to_string(), record.id.to_owned().to_string());
            result.insert("name".to_string(), record.name.to_owned());
            result.insert("code".to_string(), record.code.to_string());
            result.insert("expired_at".to_string(), record.expired_at.to_string());
            result.insert("seconds".to_string(), record.period.to_string());

            list.push(result);
        }

        Ok(list)
    }

    pub async fn query_by_name<'a>(
        pool: &Pool<MySql>,
        name: &'a str,
        key: &'a str,
    ) -> Result<Option<MySqlRow>> {
        #[rustfmt::skip]
        let statment: &str = *super::models::SELECT_STATMENT;

        let mut query_builder: sqlx::QueryBuilder<'a, sqlx::MySql> =
            sqlx::QueryBuilder::new(statment);

        query_builder.push(" where f_name = ");
        query_builder.push_bind(name);

        query_builder.push(" and f_key = ");
        query_builder.push_bind(key);

        let row = query_builder
            .build()
            .fetch_optional(pool)
            .await
            .context("query_by_name: Failed to perform a query to retrieve a otpcode.")?;

        Ok(row)
    }

    pub async fn query_by_id<'a>(
        pool: &Pool<MySql>,
        id: &'a str,
        name: &'a str,
        user_id: &'a str,
    ) -> Result<Option<MySqlRow>> {
        #[rustfmt::skip]
        let statment: &str = *super::models::SELECT_STATMENT;

        let mut query_builder: sqlx::QueryBuilder<'a, sqlx::MySql> =
            sqlx::QueryBuilder::new(statment);

        query_builder.push(" where f_id = ");
        query_builder.push_bind(string_to_number::<u64>(id)?);

        query_builder.push(" and f_name = ");
        query_builder.push_bind(name);

        query_builder.push(" and f_user_id = ");
        query_builder.push_bind(user_id);

        let row = query_builder
            .build()
            .fetch_optional(pool)
            .await
            .context("query_by_id: Failed to perform a query to retrieve a otpcode.")?;

        Ok(row)
    }

    pub async fn re_new_code(pool: &Pool<MySql>, record: &mut OtpCodeRecord) -> Result<bool> {
        record.code = crate::commons::random_number(6);
        record.expired_at = timestamp_millis() as u64 + ((record.period * 1000) as u64);

        let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new("update t_otp_code");

        query_builder.push(" set f_expired_at = ");
        query_builder.push_bind(record.expired_at);

        query_builder.push(", f_code = ");
        query_builder.push_bind(record.code);

        query_builder.push(", f_updated_at = ");
        query_builder.push_bind(timestamp_millis());

        query_builder.push(" where f_id = ");
        query_builder.push_bind(record.id);

        let update_result_int = query_builder
            .build()
            .execute(pool)
            .await
            .context("re_new_code: Failed to perform a query to update a otpcode.")?
            .rows_affected();

        Ok(update_result_int > 0)
    }
}