Skip to main content

ubiquisync_sql/db/
error.rs

1/// An error from a SQL backend operation.
2#[derive(Debug, thiserror::Error)]
3pub enum DbError {
4    /// A backend error with no more specific variant; carries the backend's
5    /// own message.
6    #[error("sql error: {0}")]
7    Sql(String),
8    /// A UNIQUE / PRIMARY KEY conflict. A tracker that keys the op-log on
9    /// `(peer_id, entry_idx)` surfaces a re-ingested entry as this — failing the
10    /// batch so the whole apply rolls back rather than double-applying, not a
11    /// silent skip. Each backend must map its native constraint error to this
12    /// variant.
13    #[error("unique constraint violation")]
14    UniqueViolation,
15    /// A column held a value of a different type than the caller requested.
16    #[error("type mismatch at column {col}: expected {expected}")]
17    TypeMismatch {
18        /// Column index that was read.
19        col: usize,
20        /// The Rust type the caller asked for.
21        expected: &'static str,
22    },
23    /// A `u64` (e.g. a packed HLC timestamp) didn't fit the signed 64-bit
24    /// integer a SQL backend stores. On a write the value exceeded `i64::MAX`;
25    /// on a read the stored value was negative. Either way it can't round-trip
26    /// through a signed column — and the signed `MAX`/`GREATEST` merge guard
27    /// would misorder it — so we reject rather than silently wrap. The `i128`
28    /// holds the offending value losslessly in both directions.
29    #[error("integer value {0} out of range for signed 64-bit storage")]
30    IntegerOutOfRange(i128),
31    /// A column index past the end of the row was requested.
32    #[error("column index {0} out of bounds")]
33    ColumnOutOfBounds(usize),
34    /// A column was SQL NULL where the caller required a non-null value.
35    #[error("unexpected null at column {0}")]
36    UnexpectedNull(usize),
37}