Skip to main content

yeti_types/error/
domain.rs

1//! Domain-specific error types that compose into [`YetiError`](super::YetiError).
2//!
3//! Each enum captures failures from one subsystem (storage, query parser,
4//! schema loader, encoder, backend manager, index). `YetiError` wraps them
5//! via `#[from]` so callers can return a subsystem error directly from
6//! crate-level APIs.
7
8use std::io;
9
10/// Storage layer errors.
11#[derive(Debug, thiserror::Error)]
12pub enum StorageError {
13    /// Key not found in storage
14    #[error("Key not found: {0}")]
15    KeyNotFound(String),
16
17    /// Write conflict (optimistic locking failure)
18    #[error("Write conflict for key: {0}")]
19    WriteConflict(String),
20
21    /// Data corruption detected
22    #[error("Corruption detected: {0}")]
23    Corruption(String),
24
25    /// I/O error (disk full, permissions, etc.)
26    #[error("I/O error: {0}")]
27    Io(#[from] io::Error),
28
29    /// RocksDB-specific error
30    #[error("RocksDB error: {0}")]
31    RocksDb(String),
32
33    /// Storage initialization failed
34    #[error("Failed to initialize storage: {0}")]
35    InitializationFailed(String),
36
37    /// Write-ahead log error
38    #[error("WAL error: {0}")]
39    Wal(String),
40}
41
42/// Query parsing and evaluation errors.
43#[derive(Debug, Clone, thiserror::Error)]
44pub enum QueryError {
45    /// FIQL query parsing failed
46    #[error("Failed to parse FIQL query: {0}")]
47    ParseError(String),
48
49    /// Invalid select field syntax
50    #[error("Invalid select field: {0}")]
51    InvalidSelectField(String),
52
53    /// Sort parameter error
54    #[error("Invalid sort parameter: {0}")]
55    InvalidSort(String),
56
57    /// Pagination parameter error
58    #[error("Invalid pagination: {0}")]
59    InvalidPagination(String),
60
61    /// Query too complex (security limit)
62    #[error("Query too complex: {reason}")]
63    TooComplex {
64        /// Description of why the query is too complex
65        reason: String,
66    },
67}
68
69/// Schema validation and definition errors.
70#[derive(Debug, Clone, thiserror::Error)]
71pub enum SchemaError {
72    /// GraphQL schema parsing failed
73    #[error("Failed to parse GraphQL schema: {0}")]
74    ParseError(String),
75
76    /// Missing required table definition
77    #[error("Table definition not found: {0}")]
78    TableNotFound(String),
79
80    /// Missing required field definition
81    #[error("Field definition not found: {table}.{field}")]
82    FieldNotFound {
83        /// Table containing the missing field
84        table: String,
85        /// Name of the missing field
86        field: String,
87    },
88
89    /// Invalid type definition
90    #[error("Invalid type definition: {0}")]
91    InvalidType(String),
92
93    /// Invalid directive
94    #[error("Invalid directive: {0}")]
95    InvalidDirective(String),
96
97    /// Schema file I/O error
98    #[error("Failed to read schema file: {0}")]
99    FileError(String),
100
101    /// Duplicate definition
102    #[error("Duplicate definition: {0}")]
103    Duplicate(String),
104}
105
106impl From<io::Error> for SchemaError {
107    fn from(err: io::Error) -> Self {
108        Self::FileError(err.to_string())
109    }
110}
111
112/// Encoding and decoding errors.
113#[derive(Debug, Clone, thiserror::Error)]
114pub enum EncodingError {
115    /// JSON serialization error
116    #[error("JSON serialization error: {0}")]
117    Json(String),
118
119    /// Key encoding error
120    #[error("Key encoding error: {0}")]
121    KeyEncoding(String),
122
123    /// Value encoding error
124    #[error("Value encoding error: {0}")]
125    ValueEncoding(String),
126
127    /// UTF-8 decoding error
128    #[error("UTF-8 decoding error: {0}")]
129    Utf8(String),
130
131    /// Invalid binary format
132    #[error("Invalid binary format: {0}")]
133    InvalidFormat(String),
134
135    /// `MessagePack` encoding/decoding error
136    #[error("MessagePack error: {0}")]
137    MessagePack(String),
138
139    /// Invalid data during decoding
140    #[error("Invalid data: {0}")]
141    InvalidData(String),
142
143    /// Invalid type for operation
144    #[error("Invalid type: {0}")]
145    InvalidType(String),
146
147    /// Unsupported type
148    #[error("Unsupported type: {0}")]
149    UnsupportedType(String),
150}
151
152impl From<serde_json::Error> for EncodingError {
153    fn from(err: serde_json::Error) -> Self {
154        Self::Json(err.to_string())
155    }
156}
157
158impl From<std::str::Utf8Error> for EncodingError {
159    fn from(err: std::str::Utf8Error) -> Self {
160        Self::Utf8(err.to_string())
161    }
162}
163
164/// Backend management errors.
165#[derive(Debug, Clone, thiserror::Error)]
166pub enum BackendError {
167    /// Backend type not supported or not initialized
168    #[error("Backend not available: {backend_type}")]
169    NotAvailable {
170        /// Backend type that is not available
171        backend_type: String,
172    },
173
174    /// Backend initialization failed
175    #[error("Failed to initialize backend '{backend_type}': {reason}")]
176    InitializationFailed {
177        /// Backend type that failed to initialize
178        backend_type: String,
179        /// Reason for the initialization failure
180        reason: String,
181    },
182
183    /// Backend configuration error
184    #[error("Backend configuration error: {0}")]
185    ConfigError(String),
186
187    /// Table-to-backend mapping not found
188    #[error("No backend mapping found for table: {0}")]
189    MappingNotFound(String),
190}
191
192/// Index-related errors.
193#[derive(Debug, Clone, thiserror::Error)]
194pub enum IndexError {
195    /// Index not found
196    #[error("Index not found: {table}.{attribute}")]
197    NotFound {
198        /// Table containing the missing index
199        table: String,
200        /// Attribute that was expected to be indexed
201        attribute: String,
202    },
203
204    /// Index corruption detected
205    #[error("Index corruption detected: {0}")]
206    Corruption(String),
207
208    /// Index update failed
209    #[error("Failed to update index: {0}")]
210    UpdateFailed(String),
211
212    /// Index scan error
213    #[error("Index scan error: {0}")]
214    ScanError(String),
215}
216
217// StorageError carries an io::Error which isn't Clone, so we hand-roll Clone.
218impl Clone for StorageError {
219    fn clone(&self) -> Self {
220        match self {
221            Self::KeyNotFound(s) => Self::KeyNotFound(s.clone()),
222            Self::WriteConflict(s) => Self::WriteConflict(s.clone()),
223            Self::Corruption(s) => Self::Corruption(s.clone()),
224            Self::Io(e) => Self::Io(io::Error::new(e.kind(), e.to_string())),
225            Self::RocksDb(s) => Self::RocksDb(s.clone()),
226            Self::InitializationFailed(s) => Self::InitializationFailed(s.clone()),
227            Self::Wal(s) => Self::Wal(s.clone()),
228        }
229    }
230}