Skip to main content

icydb_core/db/plan/
contract.rs

1//! Passive plan contract types shared across query/executor boundaries.
2
3#[cfg(test)]
4use crate::db::access::AccessPath;
5#[cfg(test)]
6use crate::db::intent::LoadSpec;
7use crate::db::{
8    access::AccessPlan, consistency::ReadConsistency, intent::QueryMode, predicate::Predicate,
9};
10use std::ops::{Deref, DerefMut};
11
12///
13/// OrderDirection
14/// Executor-facing ordering direction (applied after filtering).
15///
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum OrderDirection {
19    Asc,
20    Desc,
21}
22
23///
24/// OrderSpec
25/// Executor-facing ordering specification.
26///
27
28#[derive(Clone, Debug, Eq, PartialEq)]
29pub(crate) struct OrderSpec {
30    pub(crate) fields: Vec<(String, OrderDirection)>,
31}
32
33///
34/// DeleteLimitSpec
35/// Executor-facing delete bound with no offsets.
36///
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
39pub(crate) struct DeleteLimitSpec {
40    pub max_rows: u32,
41}
42
43///
44/// PageSpec
45/// Executor-facing pagination specification.
46///
47
48#[derive(Clone, Debug, Eq, PartialEq)]
49pub(crate) struct PageSpec {
50    pub limit: Option<u32>,
51    pub offset: u32,
52}
53
54///
55/// LogicalPlan
56///
57/// Pure logical query intent produced by the planner.
58///
59/// A `LogicalPlan` represents the access-independent query semantics:
60/// predicate/filter, ordering, distinct behavior, pagination/delete windows,
61/// and read-consistency mode.
62///
63/// Design notes:
64/// - Predicates are applied *after* data access
65/// - Ordering is applied after filtering
66/// - Pagination is applied after ordering (load only)
67/// - Delete limits are applied after ordering (delete only)
68/// - Missing-row policy is explicit and must not depend on access strategy
69///
70/// This struct is the logical compiler stage output and intentionally excludes
71/// access-path details.
72///
73
74#[derive(Clone, Debug, Eq, PartialEq)]
75pub(crate) struct LogicalPlan {
76    /// Load vs delete intent.
77    pub(crate) mode: QueryMode,
78
79    /// Optional residual predicate applied after access.
80    pub(crate) predicate: Option<Predicate>,
81
82    /// Optional ordering specification.
83    pub(crate) order: Option<OrderSpec>,
84
85    /// Optional distinct semantics over ordered rows.
86    pub(crate) distinct: bool,
87
88    /// Optional delete bound (delete intents only).
89    pub(crate) delete_limit: Option<DeleteLimitSpec>,
90
91    /// Optional pagination specification.
92    pub(crate) page: Option<PageSpec>,
93
94    /// Missing-row policy for execution.
95    pub(crate) consistency: ReadConsistency,
96}
97
98///
99/// AccessPlannedQuery
100///
101/// Access-planned query produced after access-path selection.
102/// Binds one pure `LogicalPlan` to one chosen `AccessPlan`.
103///
104
105#[derive(Clone, Debug, Eq, PartialEq)]
106pub(crate) struct AccessPlannedQuery<K> {
107    pub(crate) logical: LogicalPlan,
108    pub(crate) access: AccessPlan<K>,
109}
110
111impl<K> AccessPlannedQuery<K> {
112    /// Construct an access-planned query from logical + access stages.
113    #[must_use]
114    pub(crate) const fn from_parts(logical: LogicalPlan, access: AccessPlan<K>) -> Self {
115        Self { logical, access }
116    }
117
118    /// Decompose into logical + access stages.
119    #[must_use]
120    pub(crate) fn into_parts(self) -> (LogicalPlan, AccessPlan<K>) {
121        (self.logical, self.access)
122    }
123
124    /// Construct a minimal access-planned query with only an access path.
125    ///
126    /// Predicates, ordering, and pagination may be attached later.
127    #[cfg(test)]
128    pub(crate) fn new(access: AccessPath<K>, consistency: ReadConsistency) -> Self {
129        Self {
130            logical: LogicalPlan {
131                mode: QueryMode::Load(LoadSpec::new()),
132                predicate: None,
133                order: None,
134                distinct: false,
135                delete_limit: None,
136                page: None,
137                consistency,
138            },
139            access: AccessPlan::path(access),
140        }
141    }
142}
143
144impl<K> Deref for AccessPlannedQuery<K> {
145    type Target = LogicalPlan;
146
147    fn deref(&self) -> &Self::Target {
148        &self.logical
149    }
150}
151
152impl<K> DerefMut for AccessPlannedQuery<K> {
153    fn deref_mut(&mut self) -> &mut Self::Target {
154        &mut self.logical
155    }
156}