Description
I'm trying to figure out how best to catch SQL errors that I'd like to handle specifically or just bubble up, but I'm having some trouble figuring out exactly how to hold SqlState
to do this in a way that looks sensible. My first attempt was this:
client
.execute(/* snip */)
.map_err(|e|
match e.as_db_error() {
Some(dbe) => match (dbe.code(), dbe.column()) {
(&SqlState::FOREIGN_KEY_VIOLATION, Some("player_id")) => PlayerNotFound(player_id),
(&SqlState::UNIQUE_VIOLATION, Some("event_id")) => Conflict,
_ => DatastoreError(anyhow!(e)),
},
None => DatastoreError(anyhow!(e))
}
)?;
But that gives the error:
error: to use a constant of type `Cow` in a pattern, `Cow` must be annotated with `#[derive(PartialEq, Eq)]`
I can't quite figure out what's happening here, as SqlState
has #[derive(PartialEq, Eq)]
on it, but the compiler doesn't seem happy with it regardless. The workaround I've ended up with is below
client
.execute(/* snip */)
.map_err(|e|
match e.as_db_error() {
Some(dbe) => match dbe.column() {
Some("player_id") if dbe.code() == &SqlState::FOREIGN_KEY_VIOLATION => PlayerNotFound(player_id),
Some("roll_id") if dbe.code() == &SqlState::UNIQUE_VIOLATION => Conflict,
_ => DatastoreError(anyhow!(e)),
},
None => DatastoreError(anyhow!(e))
}
)?;
but it still feels like I'm missing something obvious. I'm not wild about this approach, not least because guards feel less readable than patterns, but also because the SqlState
is the primary thing I'm matching on here, the column is secondary info, and having them this way round makes that feel wrong.
I'm not sure if this report is asking for a code change to make this easier, or just a pointer in how to use the struct correctly, but any help would be appreciated either way. If this does work but in a non-obvious way I'd happily write a documentation PR for it.