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 UnsupportedFormat {
114 found: u32,
116 expected: u32,
118 },
119 Io {
121 operation: &'static str,
123 source: io::Error,
125 },
126 Traversal {
128 reason: &'static str,
130 },
131 LogCorrupt {
133 lsn: u64,
135 reason: &'static str,
137 },
138 BaseGenerationMismatch {
140 expected: u64,
142 found: u64,
144 },
145 UnknownName {
147 kind: &'static str,
149 name: String,
151 },
152 MissingProperty {
154 key: PropertyKeyId,
156 },
157 SchemaConflict {
159 name: String,
161 reason: &'static str,
163 },
164 ValueOutOfRange,
166 NoEqualityIndex {
168 key: PropertyKeyId,
170 },
171}
172
173impl DbError {
174 pub(crate) const fn io(operation: &'static str, source: io::Error) -> Self {
180 Self::Io { operation, source }
181 }
182
183 pub(crate) fn unsupported(message: impl Into<String>) -> Self {
189 Self::UnsupportedQuery {
190 message: message.into(),
191 }
192 }
193
194 pub(crate) fn invalid_projection(message: impl Into<String>) -> Self {
200 Self::InvalidProjection {
201 message: message.into(),
202 }
203 }
204
205 pub(crate) fn invalid_store(message: impl Into<String>) -> Self {
211 Self::InvalidStore {
212 message: message.into(),
213 }
214 }
215
216 pub(crate) const fn traversal(reason: &'static str) -> Self {
222 Self::Traversal { reason }
223 }
224}
225
226impl fmt::Display for DbError {
227 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
228 match self {
229 Self::AlreadyExists => formatter.write_str("database already exists"),
230 Self::NotFound => formatter.write_str("database not found"),
231 Self::WriterLockHeld => formatter.write_str("database writer lock is held"),
232 Self::IdOverflow => formatter.write_str("database ID overflow"),
233 Self::TransactionIdOverflow => formatter.write_str("transaction ID overflow"),
234 Self::CommitSeqOverflow => formatter.write_str("commit sequence overflow"),
235 Self::DuplicateCatalogName => formatter.write_str("duplicate catalog name"),
236 Self::DuplicateId => formatter.write_str("duplicate ID"),
237 Self::UnknownElement { id } => write!(formatter, "unknown element {}", id.get()),
238 Self::UnknownRelation { id } => write!(formatter, "unknown relation {}", id.get()),
239 Self::UnknownIncidence { id } => write!(formatter, "unknown incidence {}", id.get()),
240 Self::UnknownRole { id } => write!(formatter, "unknown role {}", id.get()),
241 Self::UnknownLabel { id } => write!(formatter, "unknown label {}", id.get()),
242 Self::UnknownRelationType { id } => {
243 write!(formatter, "unknown relation type {}", id.get())
244 }
245 Self::UnknownPropertyKey { id } => {
246 write!(formatter, "unknown property key {}", id.get())
247 }
248 Self::UnknownProjection { id } => write!(formatter, "unknown projection {}", id.get()),
249 Self::UnknownIndex { id } => write!(formatter, "unknown index {}", id.get()),
250 Self::PropertyTypeMismatch { expected, actual } => {
251 write!(
252 formatter,
253 "property type mismatch: expected {expected:?}, got {actual:?}"
254 )
255 }
256 Self::WrongPropertyFamily { expected, actual } => {
257 write!(
258 formatter,
259 "property family mismatch: expected {expected:?}, got {actual:?}"
260 )
261 }
262 Self::InvalidProjection { message } => {
263 write!(formatter, "invalid projection: {message}")
264 }
265 Self::EmptyQuery => formatter.write_str("empty query"),
266 Self::UnsupportedQuery { message } => write!(formatter, "unsupported query: {message}"),
267 Self::InvalidStore { message } => write!(formatter, "invalid store: {message}"),
268 Self::UnsupportedFormat { found, expected } => write!(
269 formatter,
270 "unsupported OXGDB format version: found {found}, this build requires {expected}"
271 ),
272 Self::Io { operation, source } => write!(formatter, "{operation} failed: {source}"),
273 Self::Traversal { reason } => write!(formatter, "traversal error: {reason}"),
274 Self::LogCorrupt { lsn, reason } => {
275 write!(formatter, "delta-log corrupt at lsn {lsn}: {reason}")
276 }
277 Self::BaseGenerationMismatch { expected, found } => write!(
278 formatter,
279 "base generation mismatch: superblock names {expected}, record has {found}"
280 ),
281 Self::UnknownName { kind, name } => write!(formatter, "unknown {kind} {name:?}"),
282 Self::MissingProperty { key } => {
283 write!(formatter, "missing property {}", key.get())
284 }
285 Self::SchemaConflict { name, reason } => {
286 write!(formatter, "schema conflict for {name:?}: {reason}")
287 }
288 Self::ValueOutOfRange => formatter.write_str("value out of representable i64 range"),
289 Self::NoEqualityIndex { key } => {
290 write!(
291 formatter,
292 "no equality index for property key {}",
293 key.get()
294 )
295 }
296 }
297 }
298}
299
300impl std::error::Error for DbError {
301 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
302 match self {
303 Self::Io { source, .. } => Some(source),
304 Self::Traversal { .. }
305 | Self::AlreadyExists
306 | Self::NotFound
307 | Self::WriterLockHeld
308 | Self::IdOverflow
309 | Self::TransactionIdOverflow
310 | Self::CommitSeqOverflow
311 | Self::DuplicateCatalogName
312 | Self::DuplicateId
313 | Self::UnknownElement { .. }
314 | Self::UnknownRelation { .. }
315 | Self::UnknownIncidence { .. }
316 | Self::UnknownRole { .. }
317 | Self::UnknownLabel { .. }
318 | Self::UnknownRelationType { .. }
319 | Self::UnknownPropertyKey { .. }
320 | Self::UnknownProjection { .. }
321 | Self::UnknownIndex { .. }
322 | Self::PropertyTypeMismatch { .. }
323 | Self::WrongPropertyFamily { .. }
324 | Self::InvalidProjection { .. }
325 | Self::EmptyQuery
326 | Self::UnsupportedQuery { .. }
327 | Self::InvalidStore { .. }
328 | Self::UnsupportedFormat { .. }
329 | Self::LogCorrupt { .. }
330 | Self::BaseGenerationMismatch { .. }
331 | Self::UnknownName { .. }
332 | Self::MissingProperty { .. }
333 | Self::SchemaConflict { .. }
334 | Self::ValueOutOfRange
335 | Self::NoEqualityIndex { .. } => None,
336 }
337 }
338}