use thiserror::Error;
#[derive(Debug, Error)]
pub enum RepositoryError {
#[error("Entity not found: {0}")]
NotFound(String),
#[error("Constraint violation: {0}")]
Constraint(String),
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("Invalid state: {0}")]
InvalidState(String),
#[error("Internal error: {0}")]
Internal(String),
#[error("Failed to execute query")]
QueryExecution(#[source] Box<Self>),
#[error("SQL could not be split into statements: {0}")]
SqlSplit(#[source] pg_query::Error),
#[error("Failed to execute SQL statement: {statement}")]
Statement {
statement: String,
#[source]
source: Box<Self>,
},
#[error("Failed to establish database connection")]
Connection(#[source] Box<Self>),
#[error("Failed to read SQL file {path}")]
SqlFile {
path: String,
#[source]
source: std::io::Error,
},
}
pub type DatabaseResult<T> = Result<T, RepositoryError>;
impl RepositoryError {
pub fn not_found<T: std::fmt::Display>(id: T) -> Self {
Self::NotFound(id.to_string())
}
pub fn is_serialization_failure(&self) -> bool {
match self {
Self::Database(sqlx_error) => sqlx_error.as_database_error().is_some_and(|db_error| {
let code = db_error.code().map(|c| c.to_string());
matches!(code.as_deref(), Some("40001" | "40P01"))
}),
_ => false,
}
}
pub fn constraint<T: Into<String>>(message: T) -> Self {
Self::Constraint(message.into())
}
pub fn invalid_argument<T: Into<String>>(message: T) -> Self {
Self::InvalidArgument(message.into())
}
pub fn internal<T: Into<String>>(message: T) -> Self {
Self::Internal(message.into())
}
pub fn invalid_state<T: Into<String>>(message: T) -> Self {
Self::InvalidState(message.into())
}
#[must_use]
pub const fn is_not_found(&self) -> bool {
matches!(self, Self::NotFound(_))
}
#[must_use]
pub const fn is_constraint(&self) -> bool {
matches!(self, Self::Constraint(_))
}
}
impl From<RepositoryError> for systemprompt_traits::RepositoryError {
fn from(err: RepositoryError) -> Self {
Self::database(err)
}
}