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/// PageSpec
81/// Executor-facing pagination specification.
82///
83
84#[derive(Clone, Debug, Eq, PartialEq)]
85pub(crate) struct PageSpec {
86    pub limit: Option<u32>,
87    pub offset: u32,
88}
89
90///
91/// AggregateKind
92///
93/// Canonical aggregate terminal taxonomy owned by query planning.
94/// All layers (query, explain, fingerprint, executor) must interpret aggregate
95/// terminal semantics through this single enum authority.
96/// Executor must derive traversal and fold direction exclusively from this enum.
97///
98
99#[allow(dead_code)]
100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
101pub enum AggregateKind {
102    Count,
103    Exists,
104    Min,
105    Max,
106    First,
107    Last,
108}
109
110/// Compatibility alias for grouped planning callsites.
111pub(crate) type GroupAggregateKind = AggregateKind;
112
113///
114/// GroupAggregateSpec
115///
116/// One grouped aggregate terminal specification declared at query-plan time.
117/// `target_field` remains optional so future field-target grouped terminals can
118/// reuse this contract without mutating the wrapper shape.
119///
120
121#[derive(Clone, Debug, Eq, PartialEq)]
122pub(crate) struct GroupAggregateSpec {
123    pub(crate) kind: AggregateKind,
124    pub(crate) target_field: Option<String>,
125}
126
127///
128/// FieldSlot
129///
130/// Canonical resolved field reference used by logical planning.
131/// `index` is the stable slot in `EntityModel::fields`; `field` is retained
132/// for diagnostics and explain surfaces.
133///
134
135#[derive(Clone, Debug, Eq, PartialEq)]
136pub(crate) struct FieldSlot {
137    pub(crate) index: usize,
138    pub(crate) field: String,
139}
140
141///
142/// GroupedExecutionConfig
143///
144/// Declarative grouped-execution budget policy selected by query planning.
145/// This remains planner-owned input; executor policy bridges may still apply
146/// defaults and enforcement strategy at runtime boundaries.
147///
148
149#[derive(Clone, Copy, Debug, Eq, PartialEq)]
150pub(crate) struct GroupedExecutionConfig {
151    pub(crate) max_groups: u64,
152    pub(crate) max_group_bytes: u64,
153}
154
155///
156/// GroupSpec
157///
158/// Declarative GROUP BY stage contract attached to a validated base plan.
159/// This wrapper is intentionally semantic-only; field-slot resolution and
160/// execution-mode derivation remain executor-owned boundaries.
161///
162
163#[derive(Clone, Debug, Eq, PartialEq)]
164pub(crate) struct GroupSpec {
165    pub(crate) group_fields: Vec<FieldSlot>,
166    pub(crate) aggregates: Vec<GroupAggregateSpec>,
167    pub(crate) execution: GroupedExecutionConfig,
168}
169
170///
171/// GroupHavingSymbol
172///
173/// Reference to one grouped HAVING input symbol.
174/// Group-field symbols reference resolved grouped key slots.
175/// Aggregate symbols reference grouped aggregate outputs by declaration index.
176///
177
178#[derive(Clone, Debug, Eq, PartialEq)]
179pub(crate) enum GroupHavingSymbol {
180    GroupField(FieldSlot),
181    AggregateIndex(usize),
182}
183
184///
185/// GroupHavingClause
186///
187/// One conservative grouped HAVING clause.
188/// This clause model intentionally supports one symbol-to-literal comparison
189/// and excludes arbitrary expression trees in grouped v1.
190///
191
192#[derive(Clone, Debug, Eq, PartialEq)]
193pub(crate) struct GroupHavingClause {
194    pub(crate) symbol: GroupHavingSymbol,
195    pub(crate) op: CompareOp,
196    pub(crate) value: Value,
197}
198
199///
200/// GroupHavingSpec
201///
202/// Declarative grouped HAVING specification evaluated after grouped
203/// aggregate finalization and before grouped pagination emission.
204/// Clauses are AND-composed in declaration order.
205///
206
207#[derive(Clone, Debug, Eq, PartialEq)]
208pub(crate) struct GroupHavingSpec {
209    pub(crate) clauses: Vec<GroupHavingClause>,
210}
211
212///
213/// ScalarPlan
214///
215/// Pure scalar logical query intent produced by the planner.
216///
217/// A `ScalarPlan` represents the access-independent query semantics:
218/// predicate/filter, ordering, distinct behavior, pagination/delete windows,
219/// and read-consistency mode.
220///
221/// Design notes:
222/// - Predicates are applied *after* data access
223/// - Ordering is applied after filtering
224/// - Pagination is applied after ordering (load only)
225/// - Delete limits are applied after ordering (delete only)
226/// - Missing-row policy is explicit and must not depend on access strategy
227///
228/// This struct is the logical compiler stage output and intentionally excludes
229/// access-path details.
230///
231
232#[derive(Clone, Debug, Eq, PartialEq)]
233pub(crate) struct ScalarPlan {
234    /// Load vs delete intent.
235    pub(crate) mode: QueryMode,
236
237    /// Optional residual predicate applied after access.
238    pub(crate) predicate: Option<PredicateExecutionModel>,
239
240    /// Optional ordering specification.
241    pub(crate) order: Option<OrderSpec>,
242
243    /// Optional distinct semantics over ordered rows.
244    pub(crate) distinct: bool,
245
246    /// Optional delete bound (delete intents only).
247    pub(crate) delete_limit: Option<DeleteLimitSpec>,
248
249    /// Optional pagination specification.
250    pub(crate) page: Option<PageSpec>,
251
252    /// Missing-row policy for execution.
253    pub(crate) consistency: MissingRowPolicy,
254}
255
256///
257/// GroupPlan
258///
259/// Pure grouped logical intent emitted by grouped planning.
260/// Group metadata is carried through one canonical `GroupSpec` contract.
261///
262
263#[derive(Clone, Debug, Eq, PartialEq)]
264pub(crate) struct GroupPlan {
265    pub(crate) scalar: ScalarPlan,
266    pub(crate) group: GroupSpec,
267    pub(crate) having: Option<GroupHavingSpec>,
268}
269
270///
271/// LogicalPlan
272///
273/// Exclusive logical query intent emitted by planning.
274/// Scalar and grouped semantics are distinct variants by construction.
275///
276
277#[derive(Clone, Debug, Eq, PartialEq)]
278pub(crate) enum LogicalPlan {
279    Scalar(ScalarPlan),
280    Grouped(GroupPlan),
281}