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    runtime_error::{ErrorClass, ErrorOrigin, RuntimeError},
21};
22use filter::*;
23use thiserror::Error as ThisError;
24
25/// Conceptual write boundary for intended atomicity (no transactions, no rollback).
26pub(crate) struct WriteUnit {
27    _label: &'static str,
28}
29
30impl WriteUnit {
31    pub(crate) const fn new(label: &'static str) -> Self {
32        Self { _label: label }
33    }
34}
35
36///
37/// ExecutorError
38///
39
40#[derive(Debug, ThisError)]
41pub enum ExecutorError {
42    #[error("data key exists: {0}")]
43    KeyExists(DataKey),
44
45    #[error("data key not found: {0}")]
46    KeyNotFound(DataKey),
47
48    #[error("index constraint violation: {0} ({1})")]
49    IndexViolation(String, String),
50
51    #[error("index not found: {0} ({1})")]
52    IndexNotFound(String, String),
53
54    #[error("index not unique: {0} ({1})")]
55    IndexNotUnique(String, String),
56
57    #[error("index key missing: {0} ({1})")]
58    IndexKeyMissing(String, String),
59
60    #[error("index corrupted: {0} ({1}) -> {2} keys")]
61    IndexCorrupted(String, String, usize),
62
63    #[error("primary key type mismatch: expected {0}, got {1}")]
64    KeyTypeMismatch(String, String),
65
66    #[error("primary key out of range for {0}: {1}")]
67    KeyOutOfRange(String, String),
68}
69
70impl ExecutorError {
71    #[must_use]
72    /// Build an index-violation error with a formatted path/field list.
73    pub(crate) fn index_violation(path: &str, index_fields: &[&str]) -> Self {
74        Self::IndexViolation(path.to_string(), index_fields.join(", "))
75    }
76
77    pub(crate) const fn class(&self) -> ErrorClass {
78        match self {
79            Self::KeyExists(_) | Self::IndexViolation(_, _) => ErrorClass::Conflict,
80            Self::KeyNotFound(_) => ErrorClass::InvariantViolation,
81            Self::IndexNotFound(_, _)
82            | Self::IndexNotUnique(_, _)
83            | Self::IndexKeyMissing(_, _)
84            | Self::KeyTypeMismatch(_, _)
85            | Self::KeyOutOfRange(_, _) => ErrorClass::Unsupported,
86            Self::IndexCorrupted(_, _, _) => ErrorClass::Corruption,
87        }
88    }
89
90    pub(crate) const fn origin(&self) -> ErrorOrigin {
91        match self {
92            Self::KeyExists(_) | Self::KeyNotFound(_) => ErrorOrigin::Store,
93            Self::IndexViolation(_, _)
94            | Self::IndexNotFound(_, _)
95            | Self::IndexNotUnique(_, _)
96            | Self::IndexKeyMissing(_, _)
97            | Self::IndexCorrupted(_, _, _) => ErrorOrigin::Index,
98            Self::KeyTypeMismatch(_, _) | Self::KeyOutOfRange(_, _) => ErrorOrigin::Executor,
99        }
100    }
101}
102
103impl From<ExecutorError> for RuntimeError {
104    fn from(err: ExecutorError) -> Self {
105        Self::new(err.class(), err.origin(), err.to_string())
106    }
107}