Skip to main content

systemprompt_database/
error.rs

1//! Typed error boundary for the database crate.
2//!
3//! `RepositoryError` is the canonical error returned from the crate's
4//! database-facing public signatures, including the dyn-safe
5//! `DatabaseProvider` / `DatabaseTransaction` trait surfaces. It composes
6//! `sqlx::Error` and `serde_json::Error` via `#[from]`; runtime invariant
7//! failures are routed through `RepositoryError::InvalidState`.
8//!
9//! Copyright (c) systemprompt.io — Business Source License 1.1.
10//! See <https://systemprompt.io> for licensing details.
11
12use thiserror::Error;
13
14#[derive(Debug, Error)]
15pub enum RepositoryError {
16    #[error("Entity not found: {0}")]
17    NotFound(String),
18
19    #[error("Constraint violation: {0}")]
20    Constraint(String),
21
22    #[error("Database error: {0}")]
23    Database(#[from] sqlx::Error),
24
25    #[error("Serialization error: {0}")]
26    Serialization(#[from] serde_json::Error),
27
28    #[error("Invalid argument: {0}")]
29    InvalidArgument(String),
30
31    #[error("Invalid state: {0}")]
32    InvalidState(String),
33
34    #[error("Internal error: {0}")]
35    Internal(String),
36
37    #[error("Failed to execute query")]
38    QueryExecution(#[source] Box<Self>),
39}
40
41pub type DatabaseResult<T> = Result<T, RepositoryError>;
42
43impl RepositoryError {
44    pub fn not_found<T: std::fmt::Display>(id: T) -> Self {
45        Self::NotFound(id.to_string())
46    }
47
48    pub fn constraint<T: Into<String>>(message: T) -> Self {
49        Self::Constraint(message.into())
50    }
51
52    pub fn invalid_argument<T: Into<String>>(message: T) -> Self {
53        Self::InvalidArgument(message.into())
54    }
55
56    pub fn internal<T: Into<String>>(message: T) -> Self {
57        Self::Internal(message.into())
58    }
59
60    pub fn invalid_state<T: Into<String>>(message: T) -> Self {
61        Self::InvalidState(message.into())
62    }
63
64    #[must_use]
65    pub const fn is_not_found(&self) -> bool {
66        matches!(self, Self::NotFound(_))
67    }
68
69    #[must_use]
70    pub const fn is_constraint(&self) -> bool {
71        matches!(self, Self::Constraint(_))
72    }
73}
74
75impl From<RepositoryError> for systemprompt_traits::RepositoryError {
76    fn from(err: RepositoryError) -> Self {
77        Self::Database(Box::new(err))
78    }
79}