use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonSchemaError(pub String);
impl fmt::Display for HaysonSchemaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for HaysonSchemaError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ValidationIssue {
pub field: String,
pub reason: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonValidationError {
pub table: String,
pub issues: Vec<ValidationIssue>,
}
impl fmt::Display for HaysonValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let detail = self
.issues
.iter()
.map(|issue| format!("{}: {}", issue.field, issue.reason))
.collect::<Vec<_>>()
.join("; ");
write!(f, "record rejected by schema of table \"{}\" — {}", self.table, detail)
}
}
impl std::error::Error for HaysonValidationError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonUniqueViolationError {
pub table: String,
pub field: String,
pub holder: String,
}
impl fmt::Display for HaysonUniqueViolationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"unique field \"{}\" of table \"{}\" is already taken by key \"{}\"",
self.field, self.table, self.holder
)
}
}
impl std::error::Error for HaysonUniqueViolationError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonRelationViolationError {
pub relation: String,
pub table: String,
pub field: String,
pub value: String,
}
impl fmt::Display for HaysonRelationViolationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"relation \"{}\" refuses \"{}\".\"{}\" = {}: no record on the other side of the relation matches it",
self.relation, self.table, self.field, self.value
)
}
}
impl std::error::Error for HaysonRelationViolationError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonRelationRestrictError {
pub relation: String,
pub table: String,
pub key: String,
pub referencing_table: String,
pub referencing_field: String,
pub referencing: usize,
}
impl fmt::Display for HaysonRelationRestrictError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"relation \"{}\" refuses deleting \"{}\".\"{}\": {} record(s) of \"{}\" still point at it through \"{}\"",
self.relation, self.table, self.key, self.referencing, self.referencing_table, self.referencing_field
)
}
}
impl std::error::Error for HaysonRelationRestrictError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonPendingConflictError {
pub table: String,
pub key: String,
pub fields: Vec<String>,
}
impl fmt::Display for HaysonPendingConflictError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let list = self
.fields
.iter()
.map(|field| format!("\"{field}\""))
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"key \"{}\" of table \"{}\" already has a queued change on {} — pass force to overwrite it",
self.key, self.table, list
)
}
}
impl std::error::Error for HaysonPendingConflictError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonCorruptLogError {
pub path: String,
pub offset: u64,
pub reason: String,
}
impl fmt::Display for HaysonCorruptLogError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"log \"{}\" is corrupt at offset {}: {}",
self.path, self.offset, self.reason
)
}
}
impl std::error::Error for HaysonCorruptLogError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonIndexMismatchError {
pub path: String,
pub log_path: String,
pub watermark: u64,
pub expected_hash: String,
pub actual_hash: String,
}
impl fmt::Display for HaysonIndexMismatchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"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",
self.path, self.expected_hash, self.actual_hash
)
}
}
impl std::error::Error for HaysonIndexMismatchError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonLogReplacedError {
pub path: String,
}
impl fmt::Display for HaysonLogReplacedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"log file \"{}\" was replaced on disk while this database held it open — reopen the database before writing again",
self.path
)
}
}
impl std::error::Error for HaysonLogReplacedError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonImageClashError {
pub physical_path: String,
}
impl fmt::Display for HaysonImageClashError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"image bytes differ from the stored file \"{}\" that has the same content hash — refusing to replace it",
self.physical_path
)
}
}
impl std::error::Error for HaysonImageClashError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonImageTooLargeError {
pub bytes: u64,
pub max_bytes: u64,
}
impl fmt::Display for HaysonImageTooLargeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"image is {} bytes, over the {} byte limit this database was opened with",
self.bytes, self.max_bytes
)
}
}
impl std::error::Error for HaysonImageTooLargeError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonNotFoundError {
pub table: String,
pub key: String,
}
impl fmt::Display for HaysonNotFoundError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "key \"{}\" is not in table \"{}\"", self.key, self.table)
}
}
impl std::error::Error for HaysonNotFoundError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonQueryParseError {
pub position: usize,
pub reason: String,
}
impl fmt::Display for HaysonQueryParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"query text is invalid at position {}: {}",
self.position, self.reason
)
}
}
impl std::error::Error for HaysonQueryParseError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonPartitionError {
pub table: String,
pub field: String,
pub reason: String,
}
impl HaysonPartitionError {
pub fn new(table: impl Into<String>, field: impl Into<String>, reason: impl Into<String>) -> Self {
HaysonPartitionError {
table: table.into(),
field: field.into(),
reason: reason.into(),
}
}
}
impl fmt::Display for HaysonPartitionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"partition field \"{}\" of table \"{}\": {}",
self.field, self.table, self.reason
)
}
}
impl std::error::Error for HaysonPartitionError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HaysonCipherError {
pub table: String,
pub field: String,
pub reason: String,
pub key_id: Option<String>,
}
impl HaysonCipherError {
pub fn new(table: impl Into<String>, field: impl Into<String>, reason: impl Into<String>) -> Self {
HaysonCipherError {
table: table.into(),
field: field.into(),
reason: reason.into(),
key_id: None,
}
}
pub fn is_missing_key(&self) -> bool {
self.reason.ends_with("which was not given")
}
pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
self.key_id = Some(key_id.into());
self
}
}
impl fmt::Display for HaysonCipherError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.field == crate::crypto::STORAGE_FIELD {
write!(f, "encrypted database {}", self.reason)
} else if self.table.is_empty() {
write!(f, "cypher configuration {}", self.reason)
} else {
write!(
f,
"encrypted field \"{}\" of table \"{}\" {}",
self.field, self.table, self.reason
)
}
}
}
impl std::error::Error for HaysonCipherError {}