icydb_core/db/query/plan/
executable.rs1use 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
11pub 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 #[must_use]
32 pub fn explain(&self) -> ExplainPlan {
33 self.plan.explain()
34 }
35
36 #[must_use]
38 pub fn fingerprint(&self) -> PlanFingerprint {
39 self.plan.fingerprint()
40 }
41
42 #[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 #[must_use]
58 pub fn erase(self) -> ExecutablePlanErased {
59 ExecutablePlanErased {
60 plan: self.plan,
61 entity_path: E::PATH,
62 }
63 }
64}
65
66#[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}