Skip to main content

icydb_core/db/query/plan/
model_builder.rs

1//! Module: query::plan::model_builder
2//! Responsibility: pure logical plan-model constructors/builders.
3//! Does not own: access-plan coupling or semantic interpretation.
4//! Boundary: logical plan builders that remain independent of access planning.
5
6use crate::db::query::plan::{DeleteSpec, FieldSlot, GroupedExecutionConfig, LoadSpec};
7
8const PLANNER_DEFAULT_MAX_GROUPS: u64 = 10_000;
9const PLANNER_DEFAULT_MAX_GROUP_BYTES: u64 = 16 * 1024 * 1024;
10
11impl LoadSpec {
12    /// Create an empty load spec.
13    #[must_use]
14    pub const fn new() -> Self {
15        Self {
16            limit: None,
17            offset: 0,
18        }
19    }
20}
21
22impl DeleteSpec {
23    /// Create an empty delete spec.
24    #[must_use]
25    pub const fn new() -> Self {
26        Self {
27            limit: None,
28            offset: 0,
29        }
30    }
31}
32
33impl FieldSlot {
34    /// Build one field slot directly for tests that need custom slot shapes.
35    #[cfg(test)]
36    #[must_use]
37    pub(in crate::db) fn from_test_slot(index: usize, field: impl Into<String>) -> Self {
38        Self::unresolved(index, field)
39    }
40}
41
42impl GroupedExecutionConfig {
43    /// Build the planner-owned conservative grouped execution ceiling.
44    ///
45    /// SQL grouping has no syntax for supplying executor hard limits. Its
46    /// lowering boundary uses this finite authority so complete hash builds
47    /// can execute without turning an omitted row `LIMIT` into unbounded
48    /// retained state.
49    #[must_use]
50    pub(in crate::db) const fn planner_default_bounded() -> Self {
51        Self::with_hard_limits(PLANNER_DEFAULT_MAX_GROUPS, PLANNER_DEFAULT_MAX_GROUP_BYTES)
52    }
53
54    /// Build one grouped execution config with explicit hard limits.
55    #[must_use]
56    pub(in crate::db) const fn with_hard_limits(max_groups: u64, max_group_bytes: u64) -> Self {
57        Self {
58            max_groups,
59            max_group_bytes,
60        }
61    }
62
63    /// Build one unbounded grouped execution config.
64    #[must_use]
65    pub(in crate::db) const fn unbounded() -> Self {
66        Self::with_hard_limits(u64::MAX, u64::MAX)
67    }
68
69    /// Return grouped hard limit for maximum groups.
70    #[must_use]
71    pub(in crate::db) const fn max_groups(&self) -> u64 {
72        self.max_groups
73    }
74
75    /// Return grouped hard limit for estimated grouped bytes.
76    #[must_use]
77    pub(in crate::db) const fn max_group_bytes(&self) -> u64 {
78        self.max_group_bytes
79    }
80
81    /// Return whether both grouped hard limits are finite and non-zero.
82    #[must_use]
83    pub(in crate::db) const fn is_finite_bounded(&self) -> bool {
84        self.max_groups > 0
85            && self.max_groups < u64::MAX
86            && self.max_group_bytes > 0
87            && self.max_group_bytes < u64::MAX
88    }
89}
90
91impl Default for GroupedExecutionConfig {
92    fn default() -> Self {
93        Self::unbounded()
94    }
95}