icydb_core/db/executor/
mod.rs

1mod coerce;
2mod context;
3mod delete;
4mod filter;
5mod load;
6mod plan;
7mod save;
8mod unique;
9mod upsert;
10
11pub(crate) use context::*;
12pub use delete::DeleteExecutor;
13pub use load::LoadExecutor;
14pub use save::SaveExecutor;
15pub(crate) use unique::resolve_unique_pk;
16pub use upsert::{UniqueIndexHandle, UpsertExecutor, UpsertResult};
17
18use crate::{
19    db::store::DataKey,
20    error::{ErrorClass, ErrorOrigin, InternalError},
21};
22use filter::*;
23use thiserror::Error as ThisError;
24
25///
26/// WriteUnit
27///
28/// Conceptual write boundary for intended atomicity (no transactions, no rollback)
29/// NOTE: This is a marker only; atomicity is not enforced.
30///
31
32pub(crate) struct WriteUnit {
33    _label: &'static str,
34}
35
36impl WriteUnit {
37    pub(crate) const fn new(label: &'static str) -> Self {
38        Self { _label: label }
39    }
40}
41
42///
43/// ExecutorError
44///
45
46#[derive(Debug, ThisError)]
47pub enum ExecutorError {
48    #[error("corruption detected ({origin}): {message}")]
49    Corruption {
50        origin: ErrorOrigin,
51        message: String,
52    },
53
54    #[error("index constraint violation: {0} ({1})")]
55    IndexViolation(String, String),
56
57    #[error("index not found: {0} ({1})")]
58    IndexNotFound(String, String),
59
60    #[error("index not unique: {0} ({1})")]
61    IndexNotUnique(String, String),
62
63    #[error("index key missing: {0} ({1})")]
64    IndexKeyMissing(String, String),
65
66    #[error("data key exists: {0}")]
67    KeyExists(DataKey),
68
69    #[error("data key not found: {0}")]
70    KeyNotFound(DataKey),
71
72    #[error("primary key type mismatch: expected {0}, got {1}")]
73    KeyTypeMismatch(String, String),
74
75    #[error("primary key out of range for {0}: {1}")]
76    KeyOutOfRange(String, String),
77}
78
79impl ExecutorError {
80    #[must_use]
81    /// Build an index-violation error with a formatted path/field list.
82    pub(crate) fn index_violation(path: &str, index_fields: &[&str]) -> Self {
83        Self::IndexViolation(path.to_string(), index_fields.join(", "))
84    }
85
86    pub(crate) const fn class(&self) -> ErrorClass {
87        match self {
88            Self::KeyExists(_) | Self::IndexViolation(_, _) => ErrorClass::Conflict,
89            Self::KeyNotFound(_) => ErrorClass::InvariantViolation,
90            Self::IndexNotFound(_, _)
91            | Self::IndexNotUnique(_, _)
92            | Self::IndexKeyMissing(_, _)
93            | Self::KeyTypeMismatch(_, _)
94            | Self::KeyOutOfRange(_, _) => ErrorClass::Unsupported,
95            Self::Corruption { .. } => ErrorClass::Corruption,
96        }
97    }
98
99    pub(crate) const fn origin(&self) -> ErrorOrigin {
100        match self {
101            Self::KeyExists(_) | Self::KeyNotFound(_) => ErrorOrigin::Store,
102            Self::IndexViolation(_, _)
103            | Self::IndexNotFound(_, _)
104            | Self::IndexNotUnique(_, _)
105            | Self::IndexKeyMissing(_, _) => ErrorOrigin::Index,
106            Self::Corruption { origin, .. } => *origin,
107            Self::KeyTypeMismatch(_, _) | Self::KeyOutOfRange(_, _) => ErrorOrigin::Executor,
108        }
109    }
110
111    pub(crate) fn corruption(origin: ErrorOrigin, message: impl Into<String>) -> Self {
112        Self::Corruption {
113            origin,
114            message: message.into(),
115        }
116    }
117}
118
119impl From<ExecutorError> for InternalError {
120    fn from(err: ExecutorError) -> Self {
121        Self::new(err.class(), err.origin(), err.to_string())
122    }
123}