Skip to main content

icydb_core/db/query/plan/
executable.rs

1use crate::{
2    db::query::{
3        QueryMode,
4        plan::{ExplainPlan, LogicalPlan, PlanFingerprint},
5    },
6    error::{ErrorClass, ErrorOrigin, InternalError},
7    traits::EntityKind,
8};
9use std::marker::PhantomData;
10
11///
12/// ExecutablePlan
13///
14/// Executor-ready plan bound to a specific entity type.
15///
16
17pub struct ExecutablePlan<E: EntityKind> {
18    plan: LogicalPlan,
19    _marker: PhantomData<E>,
20}
21
22impl<E: EntityKind> ExecutablePlan<E> {
23    pub(crate) const fn new(plan: LogicalPlan) -> Self {
24        Self {
25            plan,
26            _marker: PhantomData,
27        }
28    }
29
30    /// Explain this plan without executing it.
31    #[must_use]
32    pub fn explain(&self) -> ExplainPlan {
33        self.plan.explain()
34    }
35
36    /// Compute a stable fingerprint for this plan.
37    #[must_use]
38    pub fn fingerprint(&self) -> PlanFingerprint {
39        self.plan.fingerprint()
40    }
41
42    /// Return the plan mode (load vs delete).
43    #[must_use]
44    pub(crate) const fn mode(&self) -> QueryMode {
45        self.plan.mode
46    }
47
48    pub(crate) const fn access(&self) -> &crate::db::query::plan::AccessPlan {
49        &self.plan.access
50    }
51
52    pub(crate) fn into_inner(self) -> LogicalPlan {
53        self.plan
54    }
55
56    /// Erase the entity type while preserving the validated plan and entity path.
57    #[must_use]
58    pub fn erase(self) -> ExecutablePlanErased {
59        ExecutablePlanErased {
60            plan: self.plan,
61            entity_path: E::PATH,
62        }
63    }
64}
65
66/// Opaque, entity-tagged plan used for dynamic dispatch.
67#[doc(hidden)]
68pub struct ExecutablePlanErased {
69    plan: LogicalPlan,
70    entity_path: &'static str,
71}
72
73impl ExecutablePlanErased {
74    #[doc(hidden)]
75    pub fn into_typed<E: EntityKind>(self) -> Result<ExecutablePlan<E>, InternalError> {
76        if self.entity_path != E::PATH {
77            return Err(InternalError::new(
78                ErrorClass::Unsupported,
79                ErrorOrigin::Query,
80                format!(
81                    "plan entity mismatch: expected {}, found {}",
82                    E::PATH,
83                    self.entity_path
84                ),
85            ));
86        }
87
88        Ok(ExecutablePlan::new(self.plan))
89    }
90}