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