Skip to main content

reddb_client/
error.rs

1//! Error type for `reddb-client`.
2//!
3//! Mirrors the JSON-RPC error codes used by `red rpc --stdio` so that
4//! client error mapping is consistent across all language drivers.
5//! See `PLAN_DRIVERS.md` § "Spec do protocolo stdio".
6
7use std::fmt;
8
9/// Result alias for the entire crate.
10pub type Result<T> = std::result::Result<T, ClientError>;
11
12/// Stable, machine-readable error code.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ErrorCode {
15    /// Caller passed an unsupported `connect()` URI scheme.
16    UnsupportedScheme,
17    /// URL parser rejected the connection string.
18    InvalidUri,
19    /// File backend reported an I/O failure.
20    IoError,
21    /// Engine query parser rejected the SQL.
22    QueryError,
23    /// Feature requested is gated behind a Cargo feature that wasn't enabled.
24    FeatureDisabled,
25    /// The user called a method on a closed connection.
26    ClientClosed,
27    /// Catch-all for unexpected engine failures.
28    Internal,
29    /// TCP / TLS / DNS layer reported a failure (RedWire client).
30    Network,
31    /// Wire-level decode failure or unexpected message kind.
32    Protocol,
33    /// Server refused the credentials the client supplied.
34    AuthRefused,
35    /// Engine returned an error string in response to a Query frame.
36    Engine,
37    /// HTTP 404 / collection or resource missing.
38    NotFound,
39}
40
41impl ErrorCode {
42    pub fn as_str(self) -> &'static str {
43        match self {
44            ErrorCode::UnsupportedScheme => "UNSUPPORTED_SCHEME",
45            ErrorCode::InvalidUri => "INVALID_URI",
46            ErrorCode::IoError => "IO_ERROR",
47            ErrorCode::QueryError => "QUERY_ERROR",
48            ErrorCode::FeatureDisabled => "FEATURE_DISABLED",
49            ErrorCode::ClientClosed => "CLIENT_CLOSED",
50            ErrorCode::Internal => "INTERNAL_ERROR",
51            ErrorCode::Network => "NETWORK_ERROR",
52            ErrorCode::Protocol => "PROTOCOL_ERROR",
53            ErrorCode::AuthRefused => "AUTH_REFUSED",
54            ErrorCode::Engine => "ENGINE_ERROR",
55            ErrorCode::NotFound => "NOT_FOUND",
56        }
57    }
58}
59
60impl fmt::Display for ErrorCode {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        f.write_str(self.as_str())
63    }
64}
65
66/// Error returned by every fallible call in this crate.
67#[derive(Debug, Clone)]
68pub struct ClientError {
69    pub code: ErrorCode,
70    pub message: String,
71}
72
73impl ClientError {
74    pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
75        Self {
76            code,
77            message: message.into(),
78        }
79    }
80
81    pub fn unsupported_scheme(scheme: impl AsRef<str>) -> Self {
82        Self::new(
83            ErrorCode::UnsupportedScheme,
84            format!(
85                "unsupported URI scheme: '{}'. Expected 'file://', 'memory://' or 'grpc://'.",
86                scheme.as_ref()
87            ),
88        )
89    }
90
91    pub fn feature_disabled(feature: &str) -> Self {
92        Self::new(
93            ErrorCode::FeatureDisabled,
94            format!(
95                "the '{feature}' feature is not enabled. Enable it in Cargo.toml: \
96                 reddb-client = {{ version = \"…\", features = [\"{feature}\"] }}"
97            ),
98        )
99    }
100}
101
102impl fmt::Display for ClientError {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        write!(f, "[{}] {}", self.code, self.message)
105    }
106}
107
108impl std::error::Error for ClientError {}