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}
123
124impl DbError {
125 pub(crate) const fn io(operation: &'static str, source: io::Error) -> Self {
131 Self::Io { operation, source }
132 }
133
134 pub(crate) fn unsupported(message: impl Into<String>) -> Self {
140 Self::UnsupportedQuery {
141 message: message.into(),
142 }
143 }
144
145 pub(crate) fn invalid_projection(message: impl Into<String>) -> Self {
151 Self::InvalidProjection {
152 message: message.into(),
153 }
154 }
155
156 pub(crate) fn invalid_store(message: impl Into<String>) -> Self {
162 Self::InvalidStore {
163 message: message.into(),
164 }
165 }
166
167 pub(crate) const fn traversal(source: oxgraph_algo::BfsError) -> Self {
173 Self::Traversal { source }
174 }
175}
176
177impl fmt::Display for DbError {
178 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
179 match self {
180 Self::AlreadyExists => formatter.write_str("database already exists"),
181 Self::NotFound => formatter.write_str("database not found"),
182 Self::WriterLockHeld => formatter.write_str("database writer lock is held"),
183 Self::IdOverflow => formatter.write_str("database ID overflow"),
184 Self::TransactionIdOverflow => formatter.write_str("transaction ID overflow"),
185 Self::CommitSeqOverflow => formatter.write_str("commit sequence overflow"),
186 Self::DuplicateCatalogName => formatter.write_str("duplicate catalog name"),
187 Self::DuplicateId => formatter.write_str("duplicate ID"),
188 Self::UnknownElement { id } => write!(formatter, "unknown element {}", id.get()),
189 Self::UnknownRelation { id } => write!(formatter, "unknown relation {}", id.get()),
190 Self::UnknownIncidence { id } => write!(formatter, "unknown incidence {}", id.get()),
191 Self::UnknownRole { id } => write!(formatter, "unknown role {}", id.get()),
192 Self::UnknownLabel { id } => write!(formatter, "unknown label {}", id.get()),
193 Self::UnknownRelationType { id } => {
194 write!(formatter, "unknown relation type {}", id.get())
195 }
196 Self::UnknownPropertyKey { id } => {
197 write!(formatter, "unknown property key {}", id.get())
198 }
199 Self::UnknownProjection { id } => write!(formatter, "unknown projection {}", id.get()),
200 Self::UnknownIndex { id } => write!(formatter, "unknown index {}", id.get()),
201 Self::PropertyTypeMismatch { expected, actual } => {
202 write!(
203 formatter,
204 "property type mismatch: expected {expected:?}, got {actual:?}"
205 )
206 }
207 Self::WrongPropertyFamily { expected, actual } => {
208 write!(
209 formatter,
210 "property family mismatch: expected {expected:?}, got {actual:?}"
211 )
212 }
213 Self::InvalidProjection { message } => {
214 write!(formatter, "invalid projection: {message}")
215 }
216 Self::EmptyQuery => formatter.write_str("empty query"),
217 Self::UnsupportedQuery { message } => write!(formatter, "unsupported query: {message}"),
218 Self::InvalidStore { message } => write!(formatter, "invalid store: {message}"),
219 Self::Io { operation, source } => write!(formatter, "{operation} failed: {source}"),
220 Self::Traversal { source } => write!(formatter, "traversal error: {source}"),
221 }
222 }
223}
224
225impl std::error::Error for DbError {
226 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
227 match self {
228 Self::Io { source, .. } => Some(source),
229 Self::Traversal { source } => Some(source),
230 Self::AlreadyExists
231 | Self::NotFound
232 | Self::WriterLockHeld
233 | Self::IdOverflow
234 | Self::TransactionIdOverflow
235 | Self::CommitSeqOverflow
236 | Self::DuplicateCatalogName
237 | Self::DuplicateId
238 | Self::UnknownElement { .. }
239 | Self::UnknownRelation { .. }
240 | Self::UnknownIncidence { .. }
241 | Self::UnknownRole { .. }
242 | Self::UnknownLabel { .. }
243 | Self::UnknownRelationType { .. }
244 | Self::UnknownPropertyKey { .. }
245 | Self::UnknownProjection { .. }
246 | Self::UnknownIndex { .. }
247 | Self::PropertyTypeMismatch { .. }
248 | Self::WrongPropertyFamily { .. }
249 | Self::InvalidProjection { .. }
250 | Self::EmptyQuery
251 | Self::UnsupportedQuery { .. }
252 | Self::InvalidStore { .. } => None,
253 }
254 }
255}