Skip to main content

hayson_engine/
errors.rs

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)]
60pub struct HaysonPendingConflictError {
61    pub table: String,
62    pub key: String,
63    pub fields: Vec<String>,
64}
65
66impl fmt::Display for HaysonPendingConflictError {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        let list = self
69            .fields
70            .iter()
71            .map(|field| format!("\"{field}\""))
72            .collect::<Vec<_>>()
73            .join(", ");
74        write!(
75            f,
76            "key \"{}\" of table \"{}\" already has a queued change on {} — pass force to overwrite it",
77            self.key, self.table, list
78        )
79    }
80}
81
82impl std::error::Error for HaysonPendingConflictError {}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct HaysonCorruptLogError {
86    pub path: String,
87    pub offset: u64,
88    pub reason: String,
89}
90
91impl fmt::Display for HaysonCorruptLogError {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        write!(
94            f,
95            "log \"{}\" is corrupt at offset {}: {}",
96            self.path, self.offset, self.reason
97        )
98    }
99}
100
101impl std::error::Error for HaysonCorruptLogError {}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct HaysonIndexMismatchError {
105    pub path: String,
106    /// The log the snapshot claimed to describe — on a partitioned table, the one partition whose
107    /// fingerprint disagreed, not the table as a whole.
108    pub log_path: String,
109    /// Byte the snapshot claims to describe `log_path` up to; equal to that log's size, because a
110    /// snapshot whose watermark differs is stale rather than mismatched.
111    pub watermark: u64,
112    pub expected_hash: String,
113    pub actual_hash: String,
114}
115
116impl fmt::Display for HaysonIndexMismatchError {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        write!(
119            f,
120            "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",
121            self.path, self.expected_hash, self.actual_hash
122        )
123    }
124}
125
126impl std::error::Error for HaysonIndexMismatchError {}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct HaysonNotFoundError {
130    pub table: String,
131    pub key: String,
132}
133
134impl fmt::Display for HaysonNotFoundError {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        write!(f, "key \"{}\" is not in table \"{}\"", self.key, self.table)
137    }
138}
139
140impl std::error::Error for HaysonNotFoundError {}
141
142#[derive(Debug, Clone, PartialEq, Eq)]
143pub struct HaysonQueryParseError {
144    pub position: usize,
145    pub reason: String,
146}
147
148impl fmt::Display for HaysonQueryParseError {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        write!(
151            f,
152            "query text is invalid at position {}: {}",
153            self.position, self.reason
154        )
155    }
156}
157
158impl std::error::Error for HaysonQueryParseError {}
159
160/// A record cannot be placed in a partition file: its `partitionBy` value cannot name one, or the
161/// write would move an existing key out of the partition it already lives in.
162#[derive(Debug, Clone, PartialEq, Eq)]
163pub struct HaysonPartitionError {
164    pub table: String,
165    pub field: String,
166    pub reason: String,
167}
168
169impl HaysonPartitionError {
170    pub fn new(table: impl Into<String>, field: impl Into<String>, reason: impl Into<String>) -> Self {
171        HaysonPartitionError {
172            table: table.into(),
173            field: field.into(),
174            reason: reason.into(),
175        }
176    }
177}
178
179impl fmt::Display for HaysonPartitionError {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        write!(
182            f,
183            "partition field \"{}\" of table \"{}\": {}",
184            self.field, self.table, self.reason
185        )
186    }
187}
188
189impl std::error::Error for HaysonPartitionError {}
190
191/// A `cypher` field failed to seal/open, or the keyring passed to `open()` is itself unusable.
192/// `table` empty means the second case — the message drops the "of table" clause then.
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub struct HaysonCipherError {
195    pub table: String,
196    pub field: String,
197    pub reason: String,
198    pub key_id: Option<String>,
199}
200
201impl HaysonCipherError {
202    pub fn new(table: impl Into<String>, field: impl Into<String>, reason: impl Into<String>) -> Self {
203        HaysonCipherError {
204            table: table.into(),
205            field: field.into(),
206            reason: reason.into(),
207            key_id: None,
208        }
209    }
210
211    pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
212        self.key_id = Some(key_id.into());
213        self
214    }
215}
216
217impl fmt::Display for HaysonCipherError {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        if self.table.is_empty() {
220            write!(f, "cypher configuration {}", self.reason)
221        } else {
222            write!(
223                f,
224                "encrypted field \"{}\" of table \"{}\" {}",
225                self.field, self.table, self.reason
226            )
227        }
228    }
229}
230
231impl std::error::Error for HaysonCipherError {}