1use std::fmt;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct HaysonSchemaError(pub String);
5
6impl fmt::Display for HaysonSchemaError {
7 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8 write!(f, "{}", self.0)
9 }
10}
11
12impl std::error::Error for HaysonSchemaError {}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ValidationIssue {
16 pub field: String,
17 pub reason: String,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct HaysonValidationError {
22 pub table: String,
23 pub issues: Vec<ValidationIssue>,
24}
25
26impl fmt::Display for HaysonValidationError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 let detail = self
29 .issues
30 .iter()
31 .map(|issue| format!("{}: {}", issue.field, issue.reason))
32 .collect::<Vec<_>>()
33 .join("; ");
34 write!(f, "record rejected by schema of table \"{}\" — {}", self.table, detail)
35 }
36}
37
38impl std::error::Error for HaysonValidationError {}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct HaysonUniqueViolationError {
42 pub table: String,
43 pub field: String,
44 pub holder: String,
45}
46
47impl fmt::Display for HaysonUniqueViolationError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(
50 f,
51 "unique field \"{}\" of table \"{}\" is already taken by key \"{}\"",
52 self.field, self.table, self.holder
53 )
54 }
55}
56
57impl std::error::Error for HaysonUniqueViolationError {}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct HaysonRelationViolationError {
63 pub relation: String,
64 pub table: String,
65 pub field: String,
66 pub value: String,
67}
68
69impl fmt::Display for HaysonRelationViolationError {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(
72 f,
73 "relation \"{}\" refuses \"{}\".\"{}\" = {}: no record on the other side of the relation matches it",
74 self.relation, self.table, self.field, self.value
75 )
76 }
77}
78
79impl std::error::Error for HaysonRelationViolationError {}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct HaysonRelationRestrictError {
86 pub relation: String,
87 pub table: String,
88 pub key: String,
89 pub referencing_table: String,
90 pub referencing_field: String,
91 pub referencing: usize,
92}
93
94impl fmt::Display for HaysonRelationRestrictError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(
97 f,
98 "relation \"{}\" refuses deleting \"{}\".\"{}\": {} record(s) of \"{}\" still point at it through \"{}\"",
99 self.relation, self.table, self.key, self.referencing, self.referencing_table, self.referencing_field
100 )
101 }
102}
103
104impl std::error::Error for HaysonRelationRestrictError {}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct HaysonPendingConflictError {
108 pub table: String,
109 pub key: String,
110 pub fields: Vec<String>,
111}
112
113impl fmt::Display for HaysonPendingConflictError {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 let list = self
116 .fields
117 .iter()
118 .map(|field| format!("\"{field}\""))
119 .collect::<Vec<_>>()
120 .join(", ");
121 write!(
122 f,
123 "key \"{}\" of table \"{}\" already has a queued change on {} — pass force to overwrite it",
124 self.key, self.table, list
125 )
126 }
127}
128
129impl std::error::Error for HaysonPendingConflictError {}
130
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct HaysonCorruptLogError {
133 pub path: String,
134 pub offset: u64,
135 pub reason: String,
136}
137
138impl fmt::Display for HaysonCorruptLogError {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 write!(
141 f,
142 "log \"{}\" is corrupt at offset {}: {}",
143 self.path, self.offset, self.reason
144 )
145 }
146}
147
148impl std::error::Error for HaysonCorruptLogError {}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
151pub struct HaysonIndexMismatchError {
152 pub path: String,
153 pub log_path: String,
156 pub watermark: u64,
159 pub expected_hash: String,
160 pub actual_hash: String,
161}
162
163impl fmt::Display for HaysonIndexMismatchError {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 write!(
166 f,
167 "snapshot \"{}\" claims watermark and schema match the log, but its content fingerprint ({}) does not match the log's ({}) — left on disk for inspection, not silently discarded",
168 self.path, self.expected_hash, self.actual_hash
169 )
170 }
171}
172
173impl std::error::Error for HaysonIndexMismatchError {}
174
175#[derive(Debug, Clone, PartialEq, Eq)]
181pub struct HaysonLogReplacedError {
182 pub path: String,
183}
184
185impl fmt::Display for HaysonLogReplacedError {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 write!(
188 f,
189 "log file \"{}\" was replaced on disk while this database held it open — reopen the database before writing again",
190 self.path
191 )
192 }
193}
194
195impl std::error::Error for HaysonLogReplacedError {}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
202pub struct HaysonImageClashError {
203 pub physical_path: String,
204}
205
206impl fmt::Display for HaysonImageClashError {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 write!(
209 f,
210 "image bytes differ from the stored file \"{}\" that has the same content hash — refusing to replace it",
211 self.physical_path
212 )
213 }
214}
215
216impl std::error::Error for HaysonImageClashError {}
217
218#[derive(Debug, Clone, PartialEq, Eq)]
220pub struct HaysonImageTooLargeError {
221 pub bytes: u64,
222 pub max_bytes: u64,
223}
224
225impl fmt::Display for HaysonImageTooLargeError {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 write!(
228 f,
229 "image is {} bytes, over the {} byte limit this database was opened with",
230 self.bytes, self.max_bytes
231 )
232 }
233}
234
235impl std::error::Error for HaysonImageTooLargeError {}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
238pub struct HaysonNotFoundError {
239 pub table: String,
240 pub key: String,
241}
242
243impl fmt::Display for HaysonNotFoundError {
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 write!(f, "key \"{}\" is not in table \"{}\"", self.key, self.table)
246 }
247}
248
249impl std::error::Error for HaysonNotFoundError {}
250
251#[derive(Debug, Clone, PartialEq, Eq)]
252pub struct HaysonQueryParseError {
253 pub position: usize,
254 pub reason: String,
255}
256
257impl fmt::Display for HaysonQueryParseError {
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 write!(
260 f,
261 "query text is invalid at position {}: {}",
262 self.position, self.reason
263 )
264 }
265}
266
267impl std::error::Error for HaysonQueryParseError {}
268
269#[derive(Debug, Clone, PartialEq, Eq)]
272pub struct HaysonPartitionError {
273 pub table: String,
274 pub field: String,
275 pub reason: String,
276}
277
278impl HaysonPartitionError {
279 pub fn new(table: impl Into<String>, field: impl Into<String>, reason: impl Into<String>) -> Self {
280 HaysonPartitionError {
281 table: table.into(),
282 field: field.into(),
283 reason: reason.into(),
284 }
285 }
286}
287
288impl fmt::Display for HaysonPartitionError {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(
291 f,
292 "partition field \"{}\" of table \"{}\": {}",
293 self.field, self.table, self.reason
294 )
295 }
296}
297
298impl std::error::Error for HaysonPartitionError {}
299
300#[derive(Debug, Clone, PartialEq, Eq)]
303pub struct HaysonCipherError {
304 pub table: String,
305 pub field: String,
306 pub reason: String,
307 pub key_id: Option<String>,
308}
309
310impl HaysonCipherError {
311 pub fn new(table: impl Into<String>, field: impl Into<String>, reason: impl Into<String>) -> Self {
312 HaysonCipherError {
313 table: table.into(),
314 field: field.into(),
315 reason: reason.into(),
316 key_id: None,
317 }
318 }
319
320 pub fn is_missing_key(&self) -> bool {
323 self.reason.ends_with("which was not given")
324 }
325
326 pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
327 self.key_id = Some(key_id.into());
328 self
329 }
330}
331
332impl fmt::Display for HaysonCipherError {
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 if self.field == crate::crypto::STORAGE_FIELD {
335 write!(f, "encrypted database {}", self.reason)
336 } else if self.table.is_empty() {
337 write!(f, "cypher configuration {}", self.reason)
338 } else {
339 write!(
340 f,
341 "encrypted field \"{}\" of table \"{}\" {}",
342 self.field, self.table, self.reason
343 )
344 }
345 }
346}
347
348impl std::error::Error for HaysonCipherError {}