1use std::{fmt, io};
4
5use crate::{
6 ElementId, IncidenceId, IndexId, LabelId, ProjectionId, PropertyKeyId, RelationId,
7 RelationTypeId, RoleId, catalog::PropertyFamily, value::PropertyType,
8};
9
10#[derive(Debug)]
16#[non_exhaustive]
17pub enum DbError {
18 AlreadyExists,
20 NotFound,
22 WriterLockHeld,
24 IdOverflow,
26 TransactionIdOverflow,
28 CommitSeqOverflow,
30 DuplicateCatalogName,
32 DuplicateId,
34 UnknownElement {
36 id: ElementId,
38 },
39 UnknownRelation {
41 id: RelationId,
43 },
44 UnknownIncidence {
46 id: IncidenceId,
48 },
49 UnknownRole {
51 id: RoleId,
53 },
54 UnknownLabel {
56 id: LabelId,
58 },
59 UnknownRelationType {
61 id: RelationTypeId,
63 },
64 UnknownPropertyKey {
66 id: PropertyKeyId,
68 },
69 UnknownProjection {
71 id: ProjectionId,
73 },
74 UnknownIndex {
76 id: IndexId,
78 },
79 PropertyTypeMismatch {
81 expected: PropertyType,
83 actual: PropertyType,
85 },
86 WrongPropertyFamily {
88 expected: PropertyFamily,
90 actual: PropertyFamily,
92 },
93 InvalidProjection {
95 message: String,
97 },
98 EmptyQuery,
100 UnsupportedQuery {
102 message: String,
104 },
105 InvalidStore {
107 message: String,
109 },
110 Io {
112 operation: &'static str,
114 source: io::Error,
116 },
117 Traversal {
119 source: oxgraph_algo::BfsError,
121 },
122 LogCorrupt {
124 lsn: u64,
126 reason: &'static str,
128 },
129 BaseGenerationMismatch {
131 expected: u64,
133 found: u64,
135 },
136}
137
138impl DbError {
139 pub(crate) const fn io(operation: &'static str, source: io::Error) -> Self {
145 Self::Io { operation, source }
146 }
147
148 pub(crate) fn unsupported(message: impl Into<String>) -> Self {
154 Self::UnsupportedQuery {
155 message: message.into(),
156 }
157 }
158
159 pub(crate) fn invalid_projection(message: impl Into<String>) -> Self {
165 Self::InvalidProjection {
166 message: message.into(),
167 }
168 }
169
170 pub(crate) fn invalid_store(message: impl Into<String>) -> Self {
176 Self::InvalidStore {
177 message: message.into(),
178 }
179 }
180
181 pub(crate) const fn traversal(source: oxgraph_algo::BfsError) -> Self {
187 Self::Traversal { source }
188 }
189}
190
191impl fmt::Display for DbError {
192 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
193 match self {
194 Self::AlreadyExists => formatter.write_str("database already exists"),
195 Self::NotFound => formatter.write_str("database not found"),
196 Self::WriterLockHeld => formatter.write_str("database writer lock is held"),
197 Self::IdOverflow => formatter.write_str("database ID overflow"),
198 Self::TransactionIdOverflow => formatter.write_str("transaction ID overflow"),
199 Self::CommitSeqOverflow => formatter.write_str("commit sequence overflow"),
200 Self::DuplicateCatalogName => formatter.write_str("duplicate catalog name"),
201 Self::DuplicateId => formatter.write_str("duplicate ID"),
202 Self::UnknownElement { id } => write!(formatter, "unknown element {}", id.get()),
203 Self::UnknownRelation { id } => write!(formatter, "unknown relation {}", id.get()),
204 Self::UnknownIncidence { id } => write!(formatter, "unknown incidence {}", id.get()),
205 Self::UnknownRole { id } => write!(formatter, "unknown role {}", id.get()),
206 Self::UnknownLabel { id } => write!(formatter, "unknown label {}", id.get()),
207 Self::UnknownRelationType { id } => {
208 write!(formatter, "unknown relation type {}", id.get())
209 }
210 Self::UnknownPropertyKey { id } => {
211 write!(formatter, "unknown property key {}", id.get())
212 }
213 Self::UnknownProjection { id } => write!(formatter, "unknown projection {}", id.get()),
214 Self::UnknownIndex { id } => write!(formatter, "unknown index {}", id.get()),
215 Self::PropertyTypeMismatch { expected, actual } => {
216 write!(
217 formatter,
218 "property type mismatch: expected {expected:?}, got {actual:?}"
219 )
220 }
221 Self::WrongPropertyFamily { expected, actual } => {
222 write!(
223 formatter,
224 "property family mismatch: expected {expected:?}, got {actual:?}"
225 )
226 }
227 Self::InvalidProjection { message } => {
228 write!(formatter, "invalid projection: {message}")
229 }
230 Self::EmptyQuery => formatter.write_str("empty query"),
231 Self::UnsupportedQuery { message } => write!(formatter, "unsupported query: {message}"),
232 Self::InvalidStore { message } => write!(formatter, "invalid store: {message}"),
233 Self::Io { operation, source } => write!(formatter, "{operation} failed: {source}"),
234 Self::Traversal { source } => write!(formatter, "traversal error: {source}"),
235 Self::LogCorrupt { lsn, reason } => {
236 write!(formatter, "delta-log corrupt at lsn {lsn}: {reason}")
237 }
238 Self::BaseGenerationMismatch { expected, found } => write!(
239 formatter,
240 "base generation mismatch: superblock names {expected}, record has {found}"
241 ),
242 }
243 }
244}
245
246impl std::error::Error for DbError {
247 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
248 match self {
249 Self::Io { source, .. } => Some(source),
250 Self::Traversal { source } => Some(source),
251 Self::AlreadyExists
252 | Self::NotFound
253 | Self::WriterLockHeld
254 | Self::IdOverflow
255 | Self::TransactionIdOverflow
256 | Self::CommitSeqOverflow
257 | Self::DuplicateCatalogName
258 | Self::DuplicateId
259 | Self::UnknownElement { .. }
260 | Self::UnknownRelation { .. }
261 | Self::UnknownIncidence { .. }
262 | Self::UnknownRole { .. }
263 | Self::UnknownLabel { .. }
264 | Self::UnknownRelationType { .. }
265 | Self::UnknownPropertyKey { .. }
266 | Self::UnknownProjection { .. }
267 | Self::UnknownIndex { .. }
268 | Self::PropertyTypeMismatch { .. }
269 | Self::WrongPropertyFamily { .. }
270 | Self::InvalidProjection { .. }
271 | Self::EmptyQuery
272 | Self::UnsupportedQuery { .. }
273 | Self::InvalidStore { .. }
274 | Self::LogCorrupt { .. }
275 | Self::BaseGenerationMismatch { .. } => None,
276 }
277 }
278}