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}