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    /// Server does not advertise support for parameterized transport frames.
40    ParamsUnsupported,
41}
42
43impl ErrorCode {
44    pub fn as_str(self) -> &'static str {
45        match self {
46            ErrorCode::UnsupportedScheme => "UNSUPPORTED_SCHEME",
47            ErrorCode::InvalidUri => "INVALID_URI",
48            ErrorCode::IoError => "IO_ERROR",
49            ErrorCode::QueryError => "QUERY_ERROR",
50            ErrorCode::FeatureDisabled => "FEATURE_DISABLED",
51            ErrorCode::ClientClosed => "CLIENT_CLOSED",
52            ErrorCode::Internal => "INTERNAL_ERROR",
53            ErrorCode::Network => "NETWORK_ERROR",
54            ErrorCode::Protocol => "PROTOCOL_ERROR",
55            ErrorCode::AuthRefused => "AUTH_REFUSED",
56            ErrorCode::Engine => "ENGINE_ERROR",
57            ErrorCode::NotFound => "NOT_FOUND",
58            ErrorCode::ParamsUnsupported => "PARAMS_UNSUPPORTED",
59        }
60    }
61}
62
63impl fmt::Display for ErrorCode {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        f.write_str(self.as_str())
66    }
67}
68
69/// Error returned by every fallible call in this crate.
70#[derive(Debug, Clone)]
71pub struct ClientError {
72    pub code: ErrorCode,
73    pub message: String,
74}
75
76impl ClientError {
77    pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
78        Self {
79            code,
80            message: message.into(),
81        }
82    }
83
84    pub fn unsupported_scheme(scheme: impl AsRef<str>) -> Self {
85        Self::new(
86            ErrorCode::UnsupportedScheme,
87            format!(
88                "unsupported URI scheme: '{}'. Expected 'file://', 'memory://' or 'grpc://'.",
89                scheme.as_ref()
90            ),
91        )
92    }
93
94    pub fn feature_disabled(feature: &str) -> Self {
95        Self::new(
96            ErrorCode::FeatureDisabled,
97            format!(
98                "the '{feature}' feature is not enabled. Enable it in Cargo.toml: \
99                 reddb-client = {{ version = \"…\", features = [\"{feature}\"] }}"
100            ),
101        )
102    }
103}
104
105impl fmt::Display for ClientError {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        write!(f, "[{}] {}", self.code, self.message)
108    }
109}
110
111impl std::error::Error for ClientError {}