Skip to content

Matching on SqlState #756

Closed
Closed
@treuherz

Description

@treuherz

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions