In my Rust application I need special handling of duplicate key (code 11000) errors. I figured out this solution, but it looks complicated. Is there any better way?
let res = collection.insert_one(entry).await;
match res {
Ok(_) => Ok(()),
Err(e) => {
// println!("{:?}", e);
match *e.kind {
ErrorKind::Write(failure) => {
match failure {
WriteFailure::WriteError(we) => {
if we.code == 11000 { Ok(()) }
else { Err("other write failure".into()) }
},
_ => Err("other write error".into()),
}
},
_ => Err("other error".into()),
}
},
}
It's not clear if you need all of the different possible Err
values that you return here, but assuming that it's fine if you just return the original error in the other cases, this becomes a lot simpler.
First, factor out the test of "is this error a duplicate key error" into a function. This allows you to reuse this logic where you need it.
fn is_duplicate_key_error(error: &mongodb::error::Error) -> bool {
matches!(
*error.kind,
ErrorKind::Write(WriteFailure::WriteError(WriteError { code: 11000, .. }))
)
}
Now we can simply use match guards to apply this to your code, converting only this specific kind of error to success.
let res = collection.insert_one(entry).await;
match res {
Ok(_) => Ok(()),
Err(e) if is_duplicate_key_error(&e) => Ok(()),
Err(e) => Err(e),
}
If this is a very common pattern across your program, you can put it behind a Result
extension method like this:
pub trait ResultExt {
fn ignore_duplicate_key_error(self) -> Self;
}
impl ResultExt for Result<(), mongodb::error::Error> {
fn ignore_duplicate_key_error(self) -> Self {
match self {
Err(e) if is_duplicate_key_error(&e) => Ok(()),
v => v,
}
}
}
Now your code becomes:
collection
.insert_one(entry)
.await
.map(|_| ())
.ignore_duplicate_key_error()
Whether this is simpler/clearer or not is subjective, but it is a valid approach.