Skip to content

Commit

Permalink
Add constraint method to DatabaseError trait
Browse files Browse the repository at this point in the history
Override `constraint` method for `PgDatabaseError`.
  • Loading branch information
Florian Hübsch authored and mehcode committed Jan 21, 2021
1 parent d5e0f1b commit 68cf2f9
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 0 deletions.
9 changes: 9 additions & 0 deletions sqlx-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ pub trait DatabaseError: 'static + Send + Sync + StdError {

#[doc(hidden)]
fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static>;

/// Returns the name of the constraint that triggered the error, if applicable.
/// If the error was caused by a conflict of a unique index, this will be the index name.
///
/// ### Note
/// Currently only populated by the Postgres driver.
fn constraint(&self) -> Option<&str> {
None
}
}

impl dyn DatabaseError {
Expand Down
4 changes: 4 additions & 0 deletions sqlx-core/src/postgres/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,8 @@ impl DatabaseError for PgDatabaseError {
fn into_error(self: Box<Self>) -> Box<dyn Error + Send + Sync + 'static> {
self
}

fn constraint(&self) -> Option<&str> {
self.constraint()
}
}
36 changes: 36 additions & 0 deletions tests/postgres/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,42 @@ async fn it_can_inspect_errors() -> anyhow::Result<()> {
assert_eq!(err.code(), "42703");
assert_eq!(err.position(), Some(PgErrorPosition::Original(8)));
assert_eq!(err.routine(), Some("errorMissingColumn"));
assert_eq!(err.constraint(), None);

Ok(())
}

#[sqlx_macros::test]
async fn it_can_inspect_constraint_errors() -> anyhow::Result<()> {
let mut conn = new::<Postgres>().await?;

let res: Result<_, sqlx::Error> =
sqlx::query("INSERT INTO products VALUES (1, 'Product 1', 0);")
.execute(&mut conn)
.await;
let err = res.unwrap_err();

// can also do [as_database_error] or use `match ..`
let err = err.into_database_error().unwrap();

assert_eq!(
err.message(),
"new row for relation \"products\" violates check constraint \"products_price_check\""
);
assert_eq!(err.code().as_deref(), Some("23514"));

// can also do [downcast_ref]
let err: Box<PgDatabaseError> = err.downcast();

assert_eq!(err.severity(), PgSeverity::Error);
assert_eq!(
err.message(),
"new row for relation \"products\" violates check constraint \"products_price_check\""
);
assert_eq!(err.code(), "23514");
assert_eq!(err.position(), None);
assert_eq!(err.routine(), Some("ExecConstraints"));
assert_eq!(err.constraint(), Some("products_price_check"));

Ok(())
}
Expand Down
6 changes: 6 additions & 0 deletions tests/postgres/setup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ CREATE TYPE float_range AS RANGE
subtype = float8,
subtype_diff = float8mi
);

CREATE TABLE products (
product_no INTEGER,
name TEXT,
price NUMERIC CHECK (price > 0)
);

0 comments on commit 68cf2f9

Please sign in to comment.