icydb_core/db/executor/
mod.rs

1mod coerce;
2mod context;
3mod delete;
4mod filter;
5mod load;
6mod save;
7
8pub(crate) use context::*;
9pub use delete::DeleteExecutor;
10use filter::*;
11pub use load::LoadExecutor;
12pub use save::SaveExecutor;
13
14use crate::{
15    Error,
16    db::{
17        DbError,
18        primitives::FilterExpr,
19        query::{QueryPlan, QueryPlanner},
20        store::DataKey,
21    },
22    obs::metrics::Span,
23    traits::EntityKind,
24};
25use thiserror::Error as ThisError;
26
27///
28/// ExecutorError
29///
30
31#[derive(Debug, ThisError)]
32pub enum ExecutorError {
33    #[error("data key exists: {0}")]
34    KeyExists(DataKey),
35
36    #[error("data key not found: {0}")]
37    KeyNotFound(DataKey),
38
39    #[error("index constraint violation: {0} ({1})")]
40    IndexViolation(String, String),
41}
42
43impl ExecutorError {
44    #[must_use]
45    /// Build an index-violation error with a formatted path/field list.
46    pub(crate) fn index_violation(path: &str, index_fields: &[&str]) -> Self {
47        Self::IndexViolation(path.to_string(), index_fields.join(", "))
48    }
49}
50
51impl From<ExecutorError> for Error {
52    fn from(err: ExecutorError) -> Self {
53        DbError::from(err).into()
54    }
55}
56
57/// Plan a query for an entity given an optional filter.
58#[must_use]
59pub(crate) fn plan_for<E: EntityKind>(filter: Option<&FilterExpr>) -> QueryPlan {
60    QueryPlanner::new(filter).plan::<E>()
61}
62
63/// Convenience: set span rows from a usize length.
64pub(crate) const fn set_rows_from_len<E: EntityKind>(span: &mut Span<E>, len: usize) {
65    span.set_rows(len as u64);
66}