Skip to main content

oxgraph_db/
error.rs

1//! Database error surface.
2
3use std::{fmt, io};
4
5use crate::{
6    ElementId, IncidenceId, IndexId, LabelId, ProjectionId, PropertyKeyId, RelationId,
7    RelationTypeId, RoleId, catalog::PropertyFamily, value::PropertyType,
8};
9
10/// Errors raised by the `OxGraph` database product.
11///
12/// # Performance
13///
14/// Formatting is `O(message length)`.
15#[derive(Debug)]
16#[non_exhaustive]
17pub enum DbError {
18    /// Database files already exist.
19    AlreadyExists,
20    /// Database files do not exist.
21    NotFound,
22    /// Canonical ID space is exhausted.
23    IdOverflow,
24    /// Transaction ID space is exhausted.
25    TransactionIdOverflow,
26    /// Commit sequence space is exhausted.
27    CommitSeqOverflow,
28    /// Duplicate catalog name or ID.
29    DuplicateCatalogName,
30    /// Duplicate canonical ID.
31    DuplicateId,
32    /// Unknown element ID.
33    UnknownElement {
34        /// Missing element ID.
35        id: ElementId,
36    },
37    /// Unknown relation ID.
38    UnknownRelation {
39        /// Missing relation ID.
40        id: RelationId,
41    },
42    /// Unknown incidence ID.
43    UnknownIncidence {
44        /// Missing incidence ID.
45        id: IncidenceId,
46    },
47    /// Unknown role ID.
48    UnknownRole {
49        /// Missing role ID.
50        id: RoleId,
51    },
52    /// Unknown label ID.
53    UnknownLabel {
54        /// Missing label ID.
55        id: LabelId,
56    },
57    /// Unknown relation type ID.
58    UnknownRelationType {
59        /// Missing relation type ID.
60        id: RelationTypeId,
61    },
62    /// Unknown property key ID.
63    UnknownPropertyKey {
64        /// Missing property key ID.
65        id: PropertyKeyId,
66    },
67    /// Unknown projection ID.
68    UnknownProjection {
69        /// Missing projection ID.
70        id: ProjectionId,
71    },
72    /// Unknown index ID.
73    UnknownIndex {
74        /// Missing index ID.
75        id: IndexId,
76    },
77    /// Property value type mismatched the catalog schema.
78    PropertyTypeMismatch {
79        /// Expected property type.
80        expected: PropertyType,
81        /// Actual property type.
82        actual: PropertyType,
83    },
84    /// Property subject family mismatched the catalog schema.
85    WrongPropertyFamily {
86        /// Expected subject family.
87        expected: PropertyFamily,
88        /// Actual subject family.
89        actual: PropertyFamily,
90    },
91    /// Projection cannot be materialized as requested.
92    InvalidProjection {
93        /// Deterministic validation message.
94        message: String,
95    },
96    /// Query text is empty.
97    EmptyQuery,
98    /// Query text is outside the pinned profile.
99    UnsupportedQuery {
100        /// Deterministic explanation.
101        message: String,
102    },
103    /// Storage bytes are invalid.
104    InvalidStore {
105        /// Deterministic validation message.
106        message: String,
107    },
108    /// Wraps an IO error with operation context.
109    Io {
110        /// Operation that failed.
111        operation: &'static str,
112        /// Underlying IO error.
113        source: io::Error,
114    },
115    /// Wraps a JSON codec error.
116    Codec {
117        /// Underlying codec error.
118        source: serde_json::Error,
119    },
120}
121
122impl DbError {
123    /// Creates an IO error with operation context.
124    ///
125    /// # Performance
126    ///
127    /// This function is `O(1)`.
128    pub(crate) const fn io(operation: &'static str, source: io::Error) -> Self {
129        Self::Io { operation, source }
130    }
131
132    /// Creates an unsupported-query error.
133    ///
134    /// # Performance
135    ///
136    /// This function is `O(message.len())`.
137    pub(crate) fn unsupported(message: impl Into<String>) -> Self {
138        Self::UnsupportedQuery {
139            message: message.into(),
140        }
141    }
142
143    /// Creates an invalid-projection error.
144    ///
145    /// # Performance
146    ///
147    /// This function is `O(message.len())`.
148    pub(crate) fn invalid_projection(message: impl Into<String>) -> Self {
149        Self::InvalidProjection {
150            message: message.into(),
151        }
152    }
153
154    /// Creates an invalid-store error.
155    ///
156    /// # Performance
157    ///
158    /// This function is `O(message.len())`.
159    pub(crate) fn invalid_store(message: impl Into<String>) -> Self {
160        Self::InvalidStore {
161            message: message.into(),
162        }
163    }
164}
165
166impl fmt::Display for DbError {
167    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
168        match self {
169            Self::AlreadyExists => formatter.write_str("database already exists"),
170            Self::NotFound => formatter.write_str("database not found"),
171            Self::IdOverflow => formatter.write_str("database ID overflow"),
172            Self::TransactionIdOverflow => formatter.write_str("transaction ID overflow"),
173            Self::CommitSeqOverflow => formatter.write_str("commit sequence overflow"),
174            Self::DuplicateCatalogName => formatter.write_str("duplicate catalog name"),
175            Self::DuplicateId => formatter.write_str("duplicate ID"),
176            Self::UnknownElement { id } => write!(formatter, "unknown element {}", id.get()),
177            Self::UnknownRelation { id } => write!(formatter, "unknown relation {}", id.get()),
178            Self::UnknownIncidence { id } => write!(formatter, "unknown incidence {}", id.get()),
179            Self::UnknownRole { id } => write!(formatter, "unknown role {}", id.get()),
180            Self::UnknownLabel { id } => write!(formatter, "unknown label {}", id.get()),
181            Self::UnknownRelationType { id } => {
182                write!(formatter, "unknown relation type {}", id.get())
183            }
184            Self::UnknownPropertyKey { id } => {
185                write!(formatter, "unknown property key {}", id.get())
186            }
187            Self::UnknownProjection { id } => write!(formatter, "unknown projection {}", id.get()),
188            Self::UnknownIndex { id } => write!(formatter, "unknown index {}", id.get()),
189            Self::PropertyTypeMismatch { expected, actual } => {
190                write!(
191                    formatter,
192                    "property type mismatch: expected {expected:?}, got {actual:?}"
193                )
194            }
195            Self::WrongPropertyFamily { expected, actual } => {
196                write!(
197                    formatter,
198                    "property family mismatch: expected {expected:?}, got {actual:?}"
199                )
200            }
201            Self::InvalidProjection { message } => {
202                write!(formatter, "invalid projection: {message}")
203            }
204            Self::EmptyQuery => formatter.write_str("empty query"),
205            Self::UnsupportedQuery { message } => write!(formatter, "unsupported query: {message}"),
206            Self::InvalidStore { message } => write!(formatter, "invalid store: {message}"),
207            Self::Io { operation, source } => write!(formatter, "{operation} failed: {source}"),
208            Self::Codec { source } => write!(formatter, "codec error: {source}"),
209        }
210    }
211}
212
213impl std::error::Error for DbError {
214    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
215        match self {
216            Self::Io { source, .. } => Some(source),
217            Self::Codec { source } => Some(source),
218            Self::AlreadyExists
219            | Self::NotFound
220            | Self::IdOverflow
221            | Self::TransactionIdOverflow
222            | Self::CommitSeqOverflow
223            | Self::DuplicateCatalogName
224            | Self::DuplicateId
225            | Self::UnknownElement { .. }
226            | Self::UnknownRelation { .. }
227            | Self::UnknownIncidence { .. }
228            | Self::UnknownRole { .. }
229            | Self::UnknownLabel { .. }
230            | Self::UnknownRelationType { .. }
231            | Self::UnknownPropertyKey { .. }
232            | Self::UnknownProjection { .. }
233            | Self::UnknownIndex { .. }
234            | Self::PropertyTypeMismatch { .. }
235            | Self::WrongPropertyFamily { .. }
236            | Self::InvalidProjection { .. }
237            | Self::EmptyQuery
238            | Self::UnsupportedQuery { .. }
239            | Self::InvalidStore { .. } => None,
240        }
241    }
242}
243
244impl From<serde_json::Error> for DbError {
245    fn from(source: serde_json::Error) -> Self {
246        Self::Codec { source }
247    }
248}