hyperdb_api/error.rs
1// Copyright (c) 2026, Salesforce, Inc. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Error types for the pure Rust Hyper API.
5
6use hyperdb_api_core::client::ErrorKind;
7use std::error::Error as StdError;
8use thiserror::Error as ThisError;
9
10/// The error type for Hyper API operations.
11///
12/// This enum is `#[non_exhaustive]`: new variants and new fields on existing
13/// struct variants may be added in minor releases. Match arms must include a
14/// wildcard `_ =>` pattern.
15#[derive(Debug, ThisError)]
16#[non_exhaustive]
17pub enum Error {
18 /// Error from the underlying Hyper client.
19 #[error("{0}")]
20 Client(#[from] hyperdb_api_core::client::Error),
21
22 /// I/O error.
23 #[error("I/O error: {0}")]
24 Io(#[from] std::io::Error),
25
26 /// Invalid name error (empty or too long).
27 #[error("Invalid name: {0}")]
28 InvalidName(String),
29
30 /// Invalid table definition.
31 #[error("Invalid table definition: {0}")]
32 InvalidTableDefinition(String),
33
34 /// Database object not found (table, schema, etc.).
35 #[error("Not found: {0}")]
36 NotFound(String),
37
38 /// Database object already exists.
39 #[error("Already exists: {0}")]
40 AlreadyExists(String),
41
42 /// Generic error with a custom message.
43 #[error("{message}")]
44 #[non_exhaustive]
45 Other {
46 /// The error message.
47 message: String,
48 /// The underlying cause of the error, if any.
49 #[source]
50 source: Option<Box<dyn StdError + Send + Sync>>,
51 },
52}
53
54impl Error {
55 /// Creates a new error with the given message.
56 ///
57 /// This is a convenience constructor for creating generic errors.
58 pub fn new(message: impl Into<String>) -> Self {
59 Error::Other {
60 message: message.into(),
61 source: None,
62 }
63 }
64
65 /// Creates a new error with a cause.
66 ///
67 /// This is a convenience constructor for creating generic errors with a source.
68 pub fn with_cause<E>(message: impl Into<String>, cause: E) -> Self
69 where
70 E: Into<Box<dyn StdError + Send + Sync>>,
71 {
72 Error::Other {
73 message: message.into(),
74 source: Some(cause.into()),
75 }
76 }
77
78 /// Returns the error kind, if this is a client error.
79 ///
80 /// This is available when the error originates from `hyperdb_api_core::client::Error`.
81 /// Use this for matching on error categories (e.g., `ErrorKind::Connection`).
82 #[must_use]
83 pub fn kind(&self) -> Option<ErrorKind> {
84 match self {
85 Error::Client(err) => Some(err.kind()),
86 _ => None,
87 }
88 }
89
90 /// Returns the error message.
91 #[must_use]
92 pub fn message(&self) -> String {
93 self.to_string()
94 }
95
96 /// Extracts the `PostgreSQL` SQLSTATE code from the error, if available.
97 ///
98 /// This is only available for database query errors from the Hyper client.
99 ///
100 /// # Example
101 ///
102 /// ```
103 /// use hyperdb_api::Error;
104 ///
105 /// // Assuming we have a client error with SQLSTATE
106 /// // let err: Error = ...;
107 /// // if let Some("42P04") = err.sqlstate() {
108 /// // println!("Database already exists");
109 /// // }
110 /// ```
111 #[must_use]
112 pub fn sqlstate(&self) -> Option<&str> {
113 match self {
114 Error::Client(err) => err.sqlstate(),
115 _ => None,
116 }
117 }
118}
119
120impl From<std::convert::Infallible> for Error {
121 fn from(_: std::convert::Infallible) -> Self {
122 unreachable!()
123 }
124}
125
126/// Result type for Hyper API operations.
127pub type Result<T> = std::result::Result<T, Error>;