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::{
8        cursor::ContinuationSignature,
9        predicate::{CompareOp, MissingRowPolicy, PredicateExecutionModel},
10        query::plan::semantics::LogicalPushdownEligibility,
11    },
12    value::Value,
13};
14
15///
16/// QueryMode
17///
18/// Discriminates load vs delete intent at planning time.
19/// Encodes mode-specific fields so invalid states are unrepresentable.
20/// Mode checks are explicit and stable at execution time.
21///
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub enum QueryMode {
25    Load(LoadSpec),
26    Delete(DeleteSpec),
27}
28
29///
30/// LoadSpec
31///
32/// Mode-specific fields for load intents.
33/// Encodes pagination without leaking into delete intents.
34///
35#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
36pub struct LoadSpec {
37    pub limit: Option<u32>,
38    pub offset: u32,
39}
40
41///
42/// DeleteSpec
43///
44/// Mode-specific fields for delete intents.
45/// Encodes delete limits without leaking into load intents.
46///
47
48#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
49pub struct DeleteSpec {
50    pub limit: Option<u32>,
51}
52
53///
54/// OrderDirection
55/// Executor-facing ordering direction (applied after filtering).
56///
57#[derive(Clone, Copy, Debug, Eq, PartialEq)]
58pub enum OrderDirection {
59    Asc,
60    Desc,
61}
62
63///
64/// OrderSpec
65/// Executor-facing ordering specification.
66///
67
68#[derive(Clone, Debug, Eq, PartialEq)]
69pub(crate) struct OrderSpec {
70    pub(crate) fields: Vec<(String, OrderDirection)>,
71}
72
73///
74/// DeleteLimitSpec
75/// Executor-facing delete bound with no offsets.
76///
77
78#[derive(Clone, Copy, Debug, Eq, PartialEq)]
79pub(crate) struct DeleteLimitSpec {
80    pub max_rows: u32,
81}
82
83///
84/// DistinctExecutionStrategy
85///
86/// Planner-owned scalar DISTINCT execution strategy.
87/// This is execution-mechanics only and must not be used for semantic
88/// admissibility decisions.
89///
90
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
92pub(crate) enum DistinctExecutionStrategy {
93    None,
94    PreOrdered,
95    HashMaterialize,
96}
97
98impl DistinctExecutionStrategy {
99    /// Return true when scalar DISTINCT execution is enabled.
100    #[must_use]
101    pub(crate) const fn is_enabled(self) -> bool {
102        !matches!(self, Self::None)
103    }
104}
105
106///
107/// PlannerRouteProfile
108///
109/// Planner-projected route profile consumed by executor route planning.
110/// Carries planner-owned continuation policy that route/load layers must honor.
111///
112
113#[derive(Clone, Debug, Eq, PartialEq)]
114pub(in crate::db) struct PlannerRouteProfile {
115    continuation_policy: ContinuationPolicy,
116    logical_pushdown_eligibility: LogicalPushdownEligibility,
117}
118
119impl PlannerRouteProfile {
120    /// Construct one planner-projected route profile.
121    #[must_use]
122    pub(in crate::db) const fn new(
123        continuation_policy: ContinuationPolicy,
124        logical_pushdown_eligibility: LogicalPushdownEligibility,
125    ) -> Self {
126        Self {
127            continuation_policy,
128            logical_pushdown_eligibility,
129        }
130    }
131
132    /// Borrow planner-projected continuation policy contract.
133    #[must_use]
134    pub(in crate::db) const fn continuation_policy(&self) -> &ContinuationPolicy {
135        &self.continuation_policy
136    }
137
138    /// Borrow planner-owned logical pushdown eligibility contract.
139    #[must_use]
140    pub(in crate::db) const fn logical_pushdown_eligibility(&self) -> LogicalPushdownEligibility {
141        self.logical_pushdown_eligibility
142    }
143}
144
145///
146/// ContinuationPolicy
147///
148/// Planner-projected continuation contract carried into route/executor layers.
149/// This contract captures static continuation invariants and must not be
150/// rederived by route/load orchestration code.
151///
152
153#[derive(Clone, Copy, Debug, Eq, PartialEq)]
154pub(in crate::db) struct ContinuationPolicy {
155    requires_anchor: bool,
156    requires_strict_advance: bool,
157    is_grouped_safe: bool,
158}
159
160impl ContinuationPolicy {
161    /// Construct one planner-projected continuation policy contract.
162    #[must_use]
163    pub(in crate::db) const fn new(
164        requires_anchor: bool,
165        requires_strict_advance: bool,
166        is_grouped_safe: bool,
167    ) -> Self {
168        Self {
169            requires_anchor,
170            requires_strict_advance,
171            is_grouped_safe,
172        }
173    }
174
175    /// Return true when continuation resume paths require an anchor boundary.
176    #[must_use]
177    pub(in crate::db) const fn requires_anchor(self) -> bool {
178        self.requires_anchor
179    }
180
181    /// Return true when continuation resume paths require strict advancement.
182    #[must_use]
183    pub(in crate::db) const fn requires_strict_advance(self) -> bool {
184        self.requires_strict_advance
185    }
186
187    /// Return true when grouped continuation usage is semantically safe.
188    #[must_use]
189    pub(in crate::db) const fn is_grouped_safe(self) -> bool {
190        self.is_grouped_safe
191    }
192}
193
194///
195/// ExecutionShapeSignature
196///
197/// Immutable planner-projected semantic shape signature contract.
198/// Continuation transport encodes this contract; route/load consume it as a
199/// read-only execution identity boundary without re-deriving semantics.
200///
201
202#[derive(Clone, Copy, Debug, Eq, PartialEq)]
203pub(in crate::db) struct ExecutionShapeSignature {
204    continuation_signature: ContinuationSignature,
205}
206
207impl ExecutionShapeSignature {
208    /// Construct one immutable execution-shape signature contract.
209    #[must_use]
210    pub(in crate::db) const fn new(continuation_signature: ContinuationSignature) -> Self {
211        Self {
212            continuation_signature,
213        }
214    }
215
216    /// Borrow the canonical continuation signature for this execution shape.
217    #[must_use]
218    pub(in crate::db) const fn continuation_signature(self) -> ContinuationSignature {
219        self.continuation_signature
220    }
221}
222
223///
224/// PageSpec
225/// Executor-facing pagination specification.
226///
227
228#[derive(Clone, Debug, Eq, PartialEq)]
229pub(crate) struct PageSpec {
230    pub limit: Option<u32>,
231    pub offset: u32,
232}
233
234///
235/// AggregateKind
236///
237/// Canonical aggregate terminal taxonomy owned by query planning.
238/// All layers (query, explain, fingerprint, executor) must interpret aggregate
239/// terminal semantics through this single enum authority.
240/// Executor must derive traversal and fold direction exclusively from this enum.
241///
242
243#[derive(Clone, Copy, Debug, Eq, PartialEq)]
244pub enum AggregateKind {
245    Count,
246    Sum,
247    Exists,
248    Min,
249    Max,
250    First,
251    Last,
252}
253
254///
255/// GroupAggregateSpec
256///
257/// One grouped aggregate terminal specification declared at query-plan time.
258/// `target_field` remains optional so future field-target grouped terminals can
259/// reuse this contract without mutating the wrapper shape.
260///
261
262#[derive(Clone, Debug, Eq, PartialEq)]
263pub(crate) struct GroupAggregateSpec {
264    pub(crate) kind: AggregateKind,
265    pub(crate) target_field: Option<String>,
266    pub(crate) distinct: bool,
267}
268
269///
270/// FieldSlot
271///
272/// Canonical resolved field reference used by logical planning.
273/// `index` is the stable slot in `EntityModel::fields`; `field` is retained
274/// for diagnostics and explain surfaces.
275///
276
277#[derive(Clone, Debug, Eq, PartialEq)]
278pub(crate) struct FieldSlot {
279    pub(crate) index: usize,
280    pub(crate) field: String,
281}
282
283///
284/// GroupedExecutionConfig
285///
286/// Declarative grouped-execution budget policy selected by query planning.
287/// This remains planner-owned input; executor policy bridges may still apply
288/// defaults and enforcement strategy at runtime boundaries.
289///
290
291#[derive(Clone, Copy, Debug, Eq, PartialEq)]
292pub(crate) struct GroupedExecutionConfig {
293    pub(crate) max_groups: u64,
294    pub(crate) max_group_bytes: u64,
295}
296
297///
298/// GroupSpec
299///
300/// Declarative GROUP BY stage contract attached to a validated base plan.
301/// This wrapper is intentionally semantic-only; field-slot resolution and
302/// execution-mode derivation remain executor-owned boundaries.
303///
304
305#[derive(Clone, Debug, Eq, PartialEq)]
306pub(crate) struct GroupSpec {
307    pub(crate) group_fields: Vec<FieldSlot>,
308    pub(crate) aggregates: Vec<GroupAggregateSpec>,
309    pub(crate) execution: GroupedExecutionConfig,
310}
311
312///
313/// GroupHavingSymbol
314///
315/// Reference to one grouped HAVING input symbol.
316/// Group-field symbols reference resolved grouped key slots.
317/// Aggregate symbols reference grouped aggregate outputs by declaration index.
318///
319
320#[derive(Clone, Debug, Eq, PartialEq)]
321pub(crate) enum GroupHavingSymbol {
322    GroupField(FieldSlot),
323    AggregateIndex(usize),
324}
325
326///
327/// GroupHavingClause
328///
329/// One conservative grouped HAVING clause.
330/// This clause model intentionally supports one symbol-to-literal comparison
331/// and excludes arbitrary expression trees in grouped v1.
332///
333
334#[derive(Clone, Debug, Eq, PartialEq)]
335pub(crate) struct GroupHavingClause {
336    pub(crate) symbol: GroupHavingSymbol,
337    pub(crate) op: CompareOp,
338    pub(crate) value: Value,
339}
340
341///
342/// GroupHavingSpec
343///
344/// Declarative grouped HAVING specification evaluated after grouped
345/// aggregate finalization and before grouped pagination emission.
346/// Clauses are AND-composed in declaration order.
347///
348
349#[derive(Clone, Debug, Eq, PartialEq)]
350pub(crate) struct GroupHavingSpec {
351    pub(crate) clauses: Vec<GroupHavingClause>,
352}
353
354///
355/// ScalarPlan
356///
357/// Pure scalar logical query intent produced by the planner.
358///
359/// A `ScalarPlan` represents the access-independent query semantics:
360/// predicate/filter, ordering, distinct behavior, pagination/delete windows,
361/// and read-consistency mode.
362///
363/// Design notes:
364/// - Predicates are applied *after* data access
365/// - Ordering is applied after filtering
366/// - Pagination is applied after ordering (load only)
367/// - Delete limits are applied after ordering (delete only)
368/// - Missing-row policy is explicit and must not depend on access strategy
369///
370/// This struct is the logical compiler stage output and intentionally excludes
371/// access-path details.
372///
373
374#[derive(Clone, Debug, Eq, PartialEq)]
375pub(crate) struct ScalarPlan {
376    /// Load vs delete intent.
377    pub(crate) mode: QueryMode,
378
379    /// Optional residual predicate applied after access.
380    pub(crate) predicate: Option<PredicateExecutionModel>,
381
382    /// Optional ordering specification.
383    pub(crate) order: Option<OrderSpec>,
384
385    /// Optional distinct semantics over ordered rows.
386    pub(crate) distinct: bool,
387
388    /// Optional delete bound (delete intents only).
389    pub(crate) delete_limit: Option<DeleteLimitSpec>,
390
391    /// Optional pagination specification.
392    pub(crate) page: Option<PageSpec>,
393
394    /// Missing-row policy for execution.
395    pub(crate) consistency: MissingRowPolicy,
396}
397
398///
399/// GroupPlan
400///
401/// Pure grouped logical intent emitted by grouped planning.
402/// Group metadata is carried through one canonical `GroupSpec` contract.
403///
404
405#[derive(Clone, Debug, Eq, PartialEq)]
406pub(crate) struct GroupPlan {
407    pub(crate) scalar: ScalarPlan,
408    pub(crate) group: GroupSpec,
409    pub(crate) having: Option<GroupHavingSpec>,
410}
411
412///
413/// LogicalPlan
414///
415/// Exclusive logical query intent emitted by planning.
416/// Scalar and grouped semantics are distinct variants by construction.
417///
418
419#[derive(Clone, Debug, Eq, PartialEq)]
420pub(crate) enum LogicalPlan {
421    Scalar(ScalarPlan),
422    Grouped(GroupPlan),
423}