Skip to main content

es_entity/
constraint.rs

1use std::{error::Error, fmt, sync::Arc};
2
3use crate::ConstraintKind;
4
5/// Structured diagnostics. Attempted values are deliberately absent from Display.
6#[derive(Debug, Clone)]
7pub struct ConstraintDiagnostics {
8    pub table: &'static str,
9    pub constraint: &'static str,
10    pub kind: ConstraintKind,
11    source: Arc<sqlx::Error>,
12}
13impl fmt::Display for ConstraintDiagnostics {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        write!(
16            f,
17            "constraint violation on {} ({})",
18            self.table, self.constraint
19        )
20    }
21}
22impl Error for ConstraintDiagnostics {
23    fn source(&self) -> Option<&(dyn Error + 'static)> {
24        Some(self.source.as_ref())
25    }
26}
27
28/// A known constraint and the typed write input, when it can be attributed.
29/// Values may contain PII. Inspect deliberately; default Display never prints them.
30#[derive(Debug, Clone)]
31pub struct ConstraintConflict<V> {
32    pub attempted: Option<V>,
33    pub diagnostics: ConstraintDiagnostics,
34}
35impl<V> ConstraintConflict<V> {
36    #[doc(hidden)]
37    pub fn new(
38        attempted: Option<V>,
39        table: &'static str,
40        constraint: &'static str,
41        kind: ConstraintKind,
42        source: sqlx::Error,
43    ) -> Self {
44        Self {
45            attempted,
46            diagnostics: ConstraintDiagnostics {
47                table,
48                constraint,
49                kind,
50                source: Arc::new(source),
51            },
52        }
53    }
54}
55impl<V> fmt::Display for ConstraintConflict<V> {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        self.diagnostics.fmt(f)
58    }
59}
60impl<V: fmt::Debug> Error for ConstraintConflict<V> {
61    fn source(&self) -> Option<&(dyn Error + 'static)> {
62        Some(&self.diagnostics)
63    }
64}