Hello,
the operator "?" for Error propagation is very useful when you have to deal with a lot of errors.
the only problem is that it acts as a: return Err(xx);
but sometimes you need to manage a group of errors locally, as with java's try/catch.
for example, if you want to return a very specific type of error : ( I don't want to expose the sqlx error directly )
pub async fn test(dbex: impl PgExecutor<'_>) -> Result<i64, RepositoryError> {
match sqlx::query(r#"SELECT A, B, C FROM te_test"#)
.fetch_one(dbex)
.await
{
Ok(ret) => {
let a = ret.try_get(0)?; // It won't work, because you have to manage the "match" manually.
let b = ret.try_get(1)?;
let c = ret.try_get(2)?;
Ok(a+b+c)
}
Err(_e) => Err(RepositoryError::FatalError {
detail: "Database error".to_string(),
}),
}
}
this code will not work, unless you put "match" for all "try_get", what makes the code ugly.
let val1 = match ret.try_get(0) {
Ok(c) => c,
Err(_) => {
return Err(RepositoryError::ColumnNotFound {
detail: "Column not found".to_string(),
});
}
};
let val2 = match ret.try_get(1) {
Ok(c) => c,
Err(_) => {
return Err(RepositoryError::ColumnNotFound {
detail: "Column not found".to_string(),
});
}
};
let val3 = match ret.try_get(2) {
Ok(c) => c,
Err(_) => {
return Err(RepositoryError::ColumnNotFound {
detail: "Column not found".to_string(),
});
}
};
so I'm thinking, why limit the "?" to the function result?
it would be nice if we could do something like this :
try {
let a = ret.try_get(0)?;
let b = ret.try_get(1)?;
let c = ret.try_get(2)?;
Ok(a+b+c)
} catch(e) {
return Err(RepositoryError::ColumnNotFound {
detail: "Column not found".to_string(),
});
}
and so the final code becomes :
pub async fn test(dbex: impl PgExecutor<'_>) -> Result<i64, RepositoryError> {
match sqlx::query(r#"SELECT A, B, C FROM te_test"#)
.fetch_one(dbex)
.await
{
Ok(ret) => {
try {
let a = ret.try_get(0)?;
let b = ret.try_get(1)?;
let c = ret.try_get(2)?;
Ok(a+b+c)
} catch(e) {
return Err(RepositoryError::ColumnNotFound {
detail: "Column not found".to_string(),
});
}
}
Err(_e) => Err(RepositoryError::FatalError {
detail: "Database error".to_string(),
}),
}
}
with try/catch you can manage a group of errors locally .