turso_orm/error.rs
1//! The ORM error type, modeled by [`DbErr`].
2//!
3//! Every fallible operation in the crate returns [`DbErr`]. The driver's own
4//! error is wrapped transparently in [`DbErr::Driver`] so that callers keep
5//! access to its classification (busy, constraint kind, decode failure)
6//! through the helpers on [`DbErr`]; the remaining variants cover the
7//! situations the ORM layer detects itself, such as a `NotSet` primary key or
8//! an `UPDATE` that matched nothing.
9//!
10//! The enum is `#[non_exhaustive]` so that new ORM-level failure modes can be
11//! added without breaking matches downstream.
12
13use turso_orm_driver::{ConstraintKind, Error as DriverError, ErrorKind};
14
15/// The error returned by every fallible operation of the ORM.
16#[derive(Debug, thiserror::Error)]
17#[non_exhaustive]
18pub enum DbErr {
19 /// An error reported by the driver or the engine.
20 #[error(transparent)]
21 Driver(#[from] DriverError),
22 /// A row was expected but none was found.
23 #[error("record not found: {0}")]
24 RecordNotFound(String),
25 /// An `INSERT` inserted nothing, for example under `ON CONFLICT DO NOTHING`.
26 #[error("record not inserted")]
27 RecordNotInserted,
28 /// An `UPDATE` matched no row.
29 #[error("record not updated")]
30 RecordNotUpdated,
31 /// A required attribute of an active model is `NotSet`.
32 #[error("attribute not set: {0}")]
33 AttrNotSet(String),
34 /// A primary key value is missing from an active model.
35 #[error("primary key not set")]
36 PrimaryKeyNotSet,
37 /// A value had the wrong type for the target column or field.
38 #[error("type error: {0}")]
39 Type(String),
40 /// A JSON conversion failed.
41 #[error("json error: {0}")]
42 Json(String),
43 /// A migration failed.
44 #[error("migration error: {0}")]
45 Migration(String),
46 /// A free-form error raised by user code or hooks.
47 #[error("{0}")]
48 Custom(String),
49}
50
51impl DbErr {
52 /// The classification of the underlying driver error, if any.
53 ///
54 /// ORM-level variants carry no driver classification and yield `None`.
55 pub fn kind(&self) -> Option<ErrorKind> {
56 match self {
57 DbErr::Driver(e) => Some(e.kind()),
58 _ => None,
59 }
60 }
61
62 /// The violated constraint, when this wraps a constraint error.
63 pub fn constraint(&self) -> Option<ConstraintKind> {
64 match self {
65 DbErr::Driver(e) => e.constraint(),
66 _ => None,
67 }
68 }
69
70 /// Whether the error is transient lock contention worth retrying.
71 pub fn is_busy(&self) -> bool {
72 matches!(self, DbErr::Driver(e) if e.is_busy())
73 }
74
75 /// Whether the error is a unique-key violation.
76 pub fn is_unique_violation(&self) -> bool {
77 self.constraint() == Some(ConstraintKind::Unique)
78 }
79
80 /// Whether the error is a foreign-key violation.
81 pub fn is_foreign_key_violation(&self) -> bool {
82 self.constraint() == Some(ConstraintKind::ForeignKey)
83 }
84}
85
86/// The result alias used throughout the crate, defaulting to [`DbErr`].
87pub type Result<T, E = DbErr> = std::result::Result<T, E>;