Skip to main content

velesdb_core/velesql/ast/
aggregation.rs

1//! Aggregation types for GROUP BY and HAVING clauses.
2//!
3//! This module defines aggregate functions and grouping types
4//! used in VelesQL aggregation queries.
5
6use serde::{Deserialize, Serialize};
7
8use super::condition::CompareOp;
9use super::values::Value;
10
11/// Aggregate function type.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[non_exhaustive]
14pub enum AggregateType {
15    /// COUNT(*) or COUNT(column)
16    Count,
17    /// SUM(column)
18    Sum,
19    /// AVG(column)
20    Avg,
21    /// MIN(column)
22    Min,
23    /// MAX(column)
24    Max,
25    /// FIRST(column) — returns the value from the highest-scoring row in a group.
26    First,
27}
28
29/// Argument to an aggregate function.
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31#[non_exhaustive]
32pub enum AggregateArg {
33    /// Wildcard (*) - only valid for COUNT.
34    Wildcard,
35    /// Column reference.
36    Column(String),
37    /// The `score` pseudo-column representing `SearchResult.score`.
38    Score,
39}
40
41/// An aggregate function call in a SELECT statement.
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43pub struct AggregateFunction {
44    /// Type of aggregate function.
45    pub function_type: AggregateType,
46    /// Argument to the function.
47    pub argument: AggregateArg,
48    /// Optional alias (AS clause).
49    pub alias: Option<String>,
50}
51
52/// GROUP BY clause for aggregation queries.
53#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
54pub struct GroupByClause {
55    /// Columns to group by.
56    pub columns: Vec<String>,
57}
58
59/// Logical operator for combining HAVING conditions.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61#[non_exhaustive]
62pub enum LogicalOp {
63    /// Logical AND.
64    And,
65    /// Logical OR.
66    Or,
67}
68
69/// HAVING clause for filtering aggregation groups.
70#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
71pub struct HavingClause {
72    /// Conditions to filter groups.
73    pub conditions: Vec<HavingCondition>,
74    /// Logical operators between conditions.
75    #[serde(default)]
76    pub operators: Vec<LogicalOp>,
77}
78
79impl HavingClause {
80    /// Returns `true` if any HAVING threshold value is a scalar subquery.
81    ///
82    /// Mirrors [`Condition::has_subquery`](super::condition::Condition::has_subquery)
83    /// for HAVING thresholds, which live outside the WHERE condition tree.
84    #[must_use]
85    pub fn has_subquery(&self) -> bool {
86        self.conditions.iter().any(|cond| cond.value.is_subquery())
87    }
88
89    /// Returns `true` if any HAVING threshold value is a subquery **genuinely
90    /// correlated** against `outer_tables` (referencing one of the outer query's
91    /// tables/aliases).
92    #[must_use]
93    pub fn has_correlated_subquery(&self, outer_tables: &[&str]) -> bool {
94        self.conditions
95            .iter()
96            .any(|cond| cond.value.is_correlated_subquery_with(outer_tables))
97    }
98}
99
100/// A single HAVING condition.
101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
102pub struct HavingCondition {
103    /// Aggregate function to compare.
104    pub aggregate: AggregateFunction,
105    /// Comparison operator.
106    pub operator: CompareOp,
107    /// Value to compare against.
108    pub value: Value,
109}