Error Using SQLX in Impl block for a strcut

I have a struct and implemented some association methods, I intend to use the methods to abstract writing SQL in certain controllers.

///one time password
#[derive(Debug, Serialize, Deserialize, Validate, sqlx::FromRow, Default)]
pub struct Otp {
    pub id: Uuid,
    pub token: String,
    pub is_expired: bool,
}

/// helper function for OTP
impl Otp {
    /// create new otp;
    pub fn new() -> Self {
        let id = Uuid::new_v4();
        let token = OTP.generate(OTP_VALIDITY, *CURRENT_TIMESTAMP).unwrap();
        Self {
            id,
            token: token.to_string(),
            ..Default::default()
        }
    }

    /// save a newly created OTP to the database
    pub async fn save(&self, db_connection: &Pool<Postgres>) -> Self {
        let otp = sqlx::query_as::<_, Otp>(
            "INSERT INTO one_time_passwords (id, token)
       VALUES ($1, $2) RETURNING *",
        )
        .bind(&self.id)
        .bind(&self.token)
        .fetch_one(db_connection)
        .await
        .ok();

        if otp.is_none() {
            racoon_error!("An exception  was encountered while inserting OTP into the database");
        }
        Self { ..otp.unwrap() }
    }

Then In my controllers

 let Otp { token: otp, .. } = Otp::new()
                .save(&database)
                .await
                .link_to_user(*user_id, &database)
                .await;

But I keep getting this error

An exception  was encountered while inserting OTP into the database
thread 'tokio-runtime-worker' panicked at 'called `Option::unwrap()` on a `None` value', src/utils/otp_handler.rs:73:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Your SQL insertion can fail for a number of reasons. Without the error, it will be hard to find out why. I don't know the racoon_error! macro, but I'd propose not converting Result to Option, rewriting the save method as something akin to:


    /// save a newly created OTP to the database
    pub async fn save(&self, db_connection: &Pool<Postgres>) -> Self {
        let otp = sqlx::query_as::<_, Otp>(
            "INSERT INTO one_time_passwords (id, token)
       VALUES ($1, $2) RETURNING *",
        )
        .bind(&self.id)
        .bind(&self.token)
        .fetch_one(db_connection)
        .await;
        
        if otp.is_err() {
            racoon_error!("An exception  was encountered while inserting OTP into the database");
            // use any logging tool you see fit here
            println!("{:?}", otp);
        }
        Self { ..otp.unwrap() }
    }

This way we get to see the error and hopefully can understand what is going wrong.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.