programatik29 / tokio-rusqlite

Asynchronous handle for rusqlite library.
MIT License
89 stars 21 forks source link

Issues with passing application-specific errors #18

Closed czocher closed 1 year ago

czocher commented 1 year ago

Hello, The error design I went with for the CallFn makes it problematic to pass application-specific errors. Example:


fn failable_func(conn: &rusqlite::Connection) -> std::result::Result<(), MyError> {
    Err(MyError::MySpecificError)
}

async fn test_ergonomic_errors() -> Result<()> {
    let conn = Connection::open_in_memory().await?;

    let a = conn
        .call(|conn| failable_func(conn).map_err(|e| // What to do here? One cannot map it to any rusqlite::Error variant so there's no way to pass it co the caller)
        .await;

    Ok(())
}

// The rest is boilerplate, not really that important

#[derive(Debug)]
enum MyError {
    MySpecificError,
}

impl Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

impl std::error::Error for MyError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None // 
    }
}

I have two ideas how to solve this issue:

  1. Return to the previous version, where the function returns anything, then we'll have a Result<Result<>> issue, but the applications will be able to return anything.
  2. Change the call closure param to return tokio_rusqlite::Error and add an Other (application specific) error variant: Other(Box<dyn std::error::Error + Send + Sync + 'static>),.

Which version would you prefer?

programatik29 commented 1 year ago

Second solution is better considering users can still do Result<Result<_>> which is also true for current version.

For example:

async fn return_error() -> Result<()> {
    let conn = Connection::open_in_memory().await?;

    struct AppError;

    let result = conn.call(|_| Ok(Err::<(), _>(AppError))).await?;

    if let Err(app_error) = result {
        // ...
    }

    Ok(())
}

Adding Other variant would give a convenient choice if user doesn't care about the type or fine with downcasting.