pub struct ConstraintMap { /* private fields */ }Expand description
Consumer-registered map from DB UNIQUE-constraint violations to field-level validation errors. Construct per call site (cheap; no global state).
§First-match semantics
Entries are matched in registration order. The first entry whose Postgres
constraint name or SQLite table.column key matches the violation wins.
Register the most specific entries first when multiple UNIQUE constraints
exist on one table.
§Postgres vs SQLite identity
- Postgres: matched by constraint name via the
DatabaseError::constraint()trait method (protocol field'n'). No message-string parsing. - SQLite: matched by
table.columnextracted from the error message ("UNIQUE constraint failed: table.column"). SQLite does not expose structured constraint names so the message token is the reliable identifier.
A single registration can cover both backends by chaining .sqlite("t.c")
after .on(...).
Implementations§
Source§impl ConstraintMap
impl ConstraintMap
Sourcepub fn on(
self,
pg_constraint: impl Into<String>,
field: impl Into<String>,
message: impl Into<String>,
) -> Self
pub fn on( self, pg_constraint: impl Into<String>, field: impl Into<String>, message: impl Into<String>, ) -> Self
Register a UNIQUE constraint name → field/message mapping.
pg_constraint is the Postgres constraint name (the structured value
in the DB error protocol, e.g. "pages_slug_unique"). It is also used
as the logical entry key when chaining .sqlite(...).
Optionally chain .sqlite("table.column") immediately after to add a
SQLite discriminator to the same entry so one registration covers both
backends.
§Example
ConstraintMap::new()
.on("pages_slug_unique", "slug", "has already been taken")
.sqlite("pages.slug");Sourcepub fn sqlite(self, table_col: impl Into<String>) -> Self
pub fn sqlite(self, table_col: impl Into<String>) -> Self
Add a SQLite table.column discriminator to the LAST registered entry.
Must be chained immediately after .on(...). No-op when called without
a prior .on() call on this map.
SQLite does not expose structured constraint names; the table.column
token parsed from the error message is the reliable identifier for SQLite
backends (dev/CI environments).
Sourcepub fn try_map(&self, err: DbErr) -> Result<ValidationError, DbErr>
pub fn try_map(&self, err: DbErr) -> Result<ValidationError, DbErr>
Map a DB UNIQUE-constraint violation to a field-level ValidationError.
Returns Ok(ValidationError) when err is a UNIQUE violation that
matches a registered entry. Returns Err(err) unchanged (by move)
when:
erris not a UNIQUE violation, orerris a UNIQUE violation but no registered entry matches.
The returned ValidationError carries the entry’s field and message
and composes with .with_old_input(&data).into_action_error(url) exactly
like a Phase 190 async-rule failure.
§Safety contract (SC2)
This method NEVER swallows a DbErr. A non-matching error is returned
unchanged so the caller’s ? reaches From<DbErr> for ActionError.
Trait Implementations§
Source§impl Clone for ConstraintMap
impl Clone for ConstraintMap
Source§fn clone(&self) -> ConstraintMap
fn clone(&self) -> ConstraintMap
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Default for ConstraintMap
impl Default for ConstraintMap
Source§fn default() -> ConstraintMap
fn default() -> ConstraintMap
Auto Trait Implementations§
impl Freeze for ConstraintMap
impl RefUnwindSafe for ConstraintMap
impl Send for ConstraintMap
impl Sync for ConstraintMap
impl Unpin for ConstraintMap
impl UnsafeUnpin for ConstraintMap
impl UnwindSafe for ConstraintMap
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more