1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Module: query::plan::aggregate_shape
//! Responsibility: raw field-bearing aggregate declaration shape shared by query wrappers.
//! Does not own: aggregate semantic equality, validation, or executor state.
//! Boundary: builder and logical-plan wrappers choose their own equality over this raw shape.
use crate::db::query::plan::{
expr::{Expr, FieldId, canonicalize_aggregate_input_expr},
model::AggregateKind,
};
/// Raw aggregate declaration fields shared by builder and logical-plan wrappers.
///
/// Equality on this type is deliberately structural. Semantic aggregate
/// equality remains owned by `AggregateIdentity` and `AggregateSemanticKey`.
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct AggregateShape {
kind: AggregateKind,
input_expr: Option<Box<Expr>>,
filter_expr: Option<Box<Expr>>,
distinct: bool,
}
impl AggregateShape {
/// Construct one terminal aggregate declaration with no input expression.
#[must_use]
pub(in crate::db) const fn terminal(kind: AggregateKind) -> Self {
Self {
kind,
input_expr: None,
filter_expr: None,
distinct: false,
}
}
/// Construct one aggregate declaration over a canonical field leaf.
#[must_use]
pub(in crate::db) fn field_target(kind: AggregateKind, field: String) -> Self {
Self {
kind,
input_expr: Some(Box::new(Expr::Field(FieldId::new(field)))),
filter_expr: None,
distinct: false,
}
}
/// Construct one aggregate declaration over a canonicalized input expression.
#[must_use]
pub(in crate::db) fn from_expression_input(kind: AggregateKind, input_expr: Expr) -> Self {
Self {
kind,
input_expr: Some(Box::new(canonicalize_aggregate_input_expr(
kind, input_expr,
))),
filter_expr: None,
distinct: false,
}
}
/// Construct one aggregate declaration from an optional field input.
#[must_use]
pub(in crate::db) fn from_optional_field_input(
kind: AggregateKind,
target_field: Option<String>,
distinct: bool,
) -> Self {
Self {
kind,
input_expr: target_field.map(|field| Box::new(Expr::Field(FieldId::new(field)))),
filter_expr: None,
distinct,
}
}
/// Attach one pre-aggregate filter expression.
#[must_use]
pub(in crate::db) fn with_filter_expr(mut self, filter_expr: Expr) -> Self {
self.filter_expr = Some(Box::new(filter_expr));
self
}
/// Replace the raw authored DISTINCT bit without applying semantic normalization.
#[must_use]
pub(in crate::db) const fn with_raw_distinct(mut self, distinct: bool) -> Self {
self.distinct = distinct;
self
}
/// Replace the raw authored DISTINCT bit in place.
pub(in crate::db) const fn set_raw_distinct(&mut self, distinct: bool) {
self.distinct = distinct;
}
/// Return the aggregate kind.
#[must_use]
pub(in crate::db) const fn kind(&self) -> AggregateKind {
self.kind
}
/// Borrow the aggregate input expression, if present.
#[must_use]
pub(in crate::db) fn input_expr(&self) -> Option<&Expr> {
self.input_expr.as_deref()
}
/// Borrow the aggregate-local filter expression, if present.
#[must_use]
pub(in crate::db) fn filter_expr(&self) -> Option<&Expr> {
self.filter_expr.as_deref()
}
/// Return the raw authored DISTINCT bit.
#[must_use]
pub(in crate::db) const fn raw_distinct(&self) -> bool {
self.distinct
}
}