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}