Skip to main content

icydb_core/db/query/plan/
model.rs

1//! Module: query::plan::model
2//! Responsibility: pure logical query-plan data contracts.
3//! Does not own: constructors, plan assembly, or semantic interpretation.
4//! Boundary: data-only types shared by plan builder/semantics/validation layers.
5
6use crate::{
7    db::predicate::{CompareOp, MissingRowPolicy, PredicateExecutionModel},
8    value::Value,
9};
10
11///
12/// QueryMode
13///
14/// Discriminates load vs delete intent at planning time.
15/// Encodes mode-specific fields so invalid states are unrepresentable.
16/// Mode checks are explicit and stable at execution time.
17///
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum QueryMode {
21    Load(LoadSpec),
22    Delete(DeleteSpec),
23}
24
25///
26/// LoadSpec
27///
28/// Mode-specific fields for load intents.
29/// Encodes pagination without leaking into delete intents.
30///
31#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
32pub struct LoadSpec {
33    pub limit: Option<u32>,
34    pub offset: u32,
35}
36
37///
38/// DeleteSpec
39///
40/// Mode-specific fields for delete intents.
41/// Encodes delete limits without leaking into load intents.
42///
43
44#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
45pub struct DeleteSpec {
46    pub limit: Option<u32>,
47}
48
49///
50/// OrderDirection
51/// Executor-facing ordering direction (applied after filtering).
52///
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum OrderDirection {
55    Asc,
56    Desc,
57}
58
59///
60/// OrderSpec
61/// Executor-facing ordering specification.
62///
63
64#[derive(Clone, Debug, Eq, PartialEq)]
65pub(crate) struct OrderSpec {
66    pub(crate) fields: Vec<(String, OrderDirection)>,
67}
68
69///
70/// DeleteLimitSpec
71/// Executor-facing delete bound with no offsets.
72///
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
75pub(crate) struct DeleteLimitSpec {
76    pub max_rows: u32,
77}
78
79///
80/// DistinctExecutionStrategy
81///
82/// Planner-owned scalar DISTINCT execution strategy.
83/// This is execution-mechanics only and must not be used for semantic
84/// admissibility decisions.
85///
86
87#[derive(Clone, Copy, Debug, Eq, PartialEq)]
88pub(crate) enum DistinctExecutionStrategy {
89    None,
90    PreOrdered,
91    HashMaterialize,
92}
93
94impl DistinctExecutionStrategy {
95    /// Return true when scalar DISTINCT execution is enabled.
96    #[must_use]
97    pub(crate) const fn is_enabled(self) -> bool {
98        !matches!(self, Self::None)
99    }
100}
101
102///
103/// PageSpec
104/// Executor-facing pagination specification.
105///
106
107#[derive(Clone, Debug, Eq, PartialEq)]
108pub(crate) struct PageSpec {
109    pub limit: Option<u32>,
110    pub offset: u32,
111}
112
113///
114/// AggregateKind
115///
116/// Canonical aggregate terminal taxonomy owned by query planning.
117/// All layers (query, explain, fingerprint, executor) must interpret aggregate
118/// terminal semantics through this single enum authority.
119/// Executor must derive traversal and fold direction exclusively from this enum.
120///
121
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
123pub enum AggregateKind {
124    Count,
125    Sum,
126    Exists,
127    Min,
128    Max,
129    First,
130    Last,
131}
132
133/// Compatibility alias for grouped planning callsites.
134pub(crate) type GroupAggregateKind = AggregateKind;
135
136///
137/// GroupAggregateSpec
138///
139/// One grouped aggregate terminal specification declared at query-plan time.
140/// `target_field` remains optional so future field-target grouped terminals can
141/// reuse this contract without mutating the wrapper shape.
142///
143
144#[derive(Clone, Debug, Eq, PartialEq)]
145pub(crate) struct GroupAggregateSpec {
146    pub(crate) kind: AggregateKind,
147    pub(crate) target_field: Option<String>,
148    pub(crate) distinct: bool,
149}
150
151///
152/// FieldSlot
153///
154/// Canonical resolved field reference used by logical planning.
155/// `index` is the stable slot in `EntityModel::fields`; `field` is retained
156/// for diagnostics and explain surfaces.
157///
158
159#[derive(Clone, Debug, Eq, PartialEq)]
160pub(crate) struct FieldSlot {
161    pub(crate) index: usize,
162    pub(crate) field: String,
163}
164
165///
166/// GroupedExecutionConfig
167///
168/// Declarative grouped-execution budget policy selected by query planning.
169/// This remains planner-owned input; executor policy bridges may still apply
170/// defaults and enforcement strategy at runtime boundaries.
171///
172
173#[derive(Clone, Copy, Debug, Eq, PartialEq)]
174pub(crate) struct GroupedExecutionConfig {
175    pub(crate) max_groups: u64,
176    pub(crate) max_group_bytes: u64,
177}
178
179///
180/// GroupSpec
181///
182/// Declarative GROUP BY stage contract attached to a validated base plan.
183/// This wrapper is intentionally semantic-only; field-slot resolution and
184/// execution-mode derivation remain executor-owned boundaries.
185///
186
187#[derive(Clone, Debug, Eq, PartialEq)]
188pub(crate) struct GroupSpec {
189    pub(crate) group_fields: Vec<FieldSlot>,
190    pub(crate) aggregates: Vec<GroupAggregateSpec>,
191    pub(crate) execution: GroupedExecutionConfig,
192}
193
194///
195/// GroupHavingSymbol
196///
197/// Reference to one grouped HAVING input symbol.
198/// Group-field symbols reference resolved grouped key slots.
199/// Aggregate symbols reference grouped aggregate outputs by declaration index.
200///
201
202#[derive(Clone, Debug, Eq, PartialEq)]
203pub(crate) enum GroupHavingSymbol {
204    GroupField(FieldSlot),
205    AggregateIndex(usize),
206}
207
208///
209/// GroupHavingClause
210///
211/// One conservative grouped HAVING clause.
212/// This clause model intentionally supports one symbol-to-literal comparison
213/// and excludes arbitrary expression trees in grouped v1.
214///
215
216#[derive(Clone, Debug, Eq, PartialEq)]
217pub(crate) struct GroupHavingClause {
218    pub(crate) symbol: GroupHavingSymbol,
219    pub(crate) op: CompareOp,
220    pub(crate) value: Value,
221}
222
223///
224/// GroupHavingSpec
225///
226/// Declarative grouped HAVING specification evaluated after grouped
227/// aggregate finalization and before grouped pagination emission.
228/// Clauses are AND-composed in declaration order.
229///
230
231#[derive(Clone, Debug, Eq, PartialEq)]
232pub(crate) struct GroupHavingSpec {
233    pub(crate) clauses: Vec<GroupHavingClause>,
234}
235
236///
237/// ScalarPlan
238///
239/// Pure scalar logical query intent produced by the planner.
240///
241/// A `ScalarPlan` represents the access-independent query semantics:
242/// predicate/filter, ordering, distinct behavior, pagination/delete windows,
243/// and read-consistency mode.
244///
245/// Design notes:
246/// - Predicates are applied *after* data access
247/// - Ordering is applied after filtering
248/// - Pagination is applied after ordering (load only)
249/// - Delete limits are applied after ordering (delete only)
250/// - Missing-row policy is explicit and must not depend on access strategy
251///
252/// This struct is the logical compiler stage output and intentionally excludes
253/// access-path details.
254///
255
256#[derive(Clone, Debug, Eq, PartialEq)]
257pub(crate) struct ScalarPlan {
258    /// Load vs delete intent.
259    pub(crate) mode: QueryMode,
260
261    /// Optional residual predicate applied after access.
262    pub(crate) predicate: Option<PredicateExecutionModel>,
263
264    /// Optional ordering specification.
265    pub(crate) order: Option<OrderSpec>,
266
267    /// Optional distinct semantics over ordered rows.
268    pub(crate) distinct: bool,
269
270    /// Optional delete bound (delete intents only).
271    pub(crate) delete_limit: Option<DeleteLimitSpec>,
272
273    /// Optional pagination specification.
274    pub(crate) page: Option<PageSpec>,
275
276    /// Missing-row policy for execution.
277    pub(crate) consistency: MissingRowPolicy,
278}
279
280///
281/// GroupPlan
282///
283/// Pure grouped logical intent emitted by grouped planning.
284/// Group metadata is carried through one canonical `GroupSpec` contract.
285///
286
287#[derive(Clone, Debug, Eq, PartialEq)]
288pub(crate) struct GroupPlan {
289    pub(crate) scalar: ScalarPlan,
290    pub(crate) group: GroupSpec,
291    pub(crate) having: Option<GroupHavingSpec>,
292}
293
294///
295/// LogicalPlan
296///
297/// Exclusive logical query intent emitted by planning.
298/// Scalar and grouped semantics are distinct variants by construction.
299///
300
301#[derive(Clone, Debug, Eq, PartialEq)]
302pub(crate) enum LogicalPlan {
303    Scalar(ScalarPlan),
304    Grouped(GroupPlan),
305}