1use std::fmt::Display;
14use std::str::FromStr;
15
16use serde::{Deserialize, Serialize};
17use ts_rs::TS;
18
19use crate::proto;
20use crate::proto::view_config;
21
22#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, TS)]
23#[serde()]
24pub enum SingleAggregate {
25 #[serde(rename = "sum")]
26 Sum,
27
28 #[serde(rename = "sum abs")]
29 SumAbs,
30
31 #[serde(rename = "sum not null")]
32 SumNotNull,
33
34 #[serde(rename = "abs sum")]
35 AbsSum,
36
37 #[serde(rename = "pct sum parent")]
38 PctSumParent,
39
40 #[serde(rename = "pct sum grand total")]
41 PctSumGrandTotal,
42
43 #[serde(rename = "any")]
44 Any,
45
46 #[serde(rename = "unique")]
47 Unique,
48
49 #[serde(rename = "dominant")]
50 Dominant,
51
52 #[serde(rename = "q1")]
53 Q1,
54
55 #[serde(rename = "q3")]
56 Q3,
57
58 #[serde(rename = "median")]
59 Median,
60
61 #[serde(rename = "first by index")]
62 FirstByIndex,
63
64 #[serde(rename = "first")]
65 First,
66
67 #[serde(rename = "last by index")]
68 LastByIndex,
69
70 #[serde(rename = "last minus first")]
71 LastMinusFirst,
72
73 #[serde(rename = "last")]
74 Last,
75
76 #[serde(rename = "count")]
77 Count,
78
79 #[serde(rename = "distinct count")]
80 DistinctCount,
81
82 #[serde(rename = "avg")]
83 Avg,
84
85 #[serde(rename = "mean")]
86 Mean,
87
88 #[serde(rename = "join")]
89 Join,
90
91 #[serde(rename = "high")]
92 High,
93
94 #[serde(rename = "low")]
95 Low,
96
97 #[serde(rename = "max")]
98 Max,
99
100 #[serde(rename = "min")]
101 Min,
102
103 #[serde(rename = "high minus low")]
104 HighMinusLow,
105
106 #[serde(rename = "stddev")]
107 StdDev,
108
109 #[serde(rename = "var")]
110 Var,
111}
112
113impl Display for SingleAggregate {
114 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
115 let term = match self {
116 Self::Sum => "sum",
117 Self::SumAbs => "sum abs",
118 Self::SumNotNull => "sum not null",
119 Self::AbsSum => "abs sum",
120 Self::PctSumParent => "pct sum parent",
121 Self::PctSumGrandTotal => "pct sum grand total",
122 Self::Any => "any",
123 Self::Unique => "unique",
124 Self::Dominant => "dominant",
125 Self::Median => "median",
126 Self::Q1 => "q1",
127 Self::Q3 => "q3",
128 Self::First => "first",
129 Self::FirstByIndex => "first by index",
130 Self::LastByIndex => "last by index",
131 Self::LastMinusFirst => "last minus first",
132 Self::Last => "last",
133 Self::Count => "count",
134 Self::DistinctCount => "distinct count",
135 Self::Avg => "avg",
136 Self::Mean => "mean",
137 Self::Join => "join",
138 Self::High => "high",
139 Self::Low => "low",
140 Self::HighMinusLow => "high minus low",
141 Self::StdDev => "stddev",
142 Self::Var => "var",
143 Self::Max => "max",
144 Self::Min => "min",
145 };
146
147 write!(fmt, "{}", term)
148 }
149}
150
151impl FromStr for SingleAggregate {
152 type Err = String;
153
154 fn from_str(value: &str) -> Result<Self, String> {
155 match value {
156 "sum" => Ok(Self::Sum),
157 "sum abs" => Ok(Self::SumAbs),
158 "sum not null" => Ok(Self::SumNotNull),
159 "abs sum" => Ok(Self::AbsSum),
160 "pct sum parent" => Ok(Self::PctSumParent),
161 "pct sum grand total" => Ok(Self::PctSumGrandTotal),
162 "any" => Ok(Self::Any),
163 "unique" => Ok(Self::Unique),
164 "dominant" => Ok(Self::Dominant),
165 "median" => Ok(Self::Median),
166 "q1" => Ok(Self::Q1),
167 "q3" => Ok(Self::Q3),
168 "first by index" => Ok(Self::FirstByIndex),
169 "first" => Ok(Self::First),
170 "last by index" => Ok(Self::LastByIndex),
171 "last minus first" => Ok(Self::LastMinusFirst),
172 "last" => Ok(Self::Last),
173 "count" => Ok(Self::Count),
174 "distinct count" => Ok(Self::DistinctCount),
175 "avg" => Ok(Self::Avg),
176 "mean" => Ok(Self::Mean),
177 "join" => Ok(Self::Join),
178 "high" => Ok(Self::High),
179 "low" => Ok(Self::Low),
180 "max" => Ok(Self::Max),
181 "min" => Ok(Self::Min),
182 "high minus low" => Ok(Self::HighMinusLow),
183 "stddev" => Ok(Self::StdDev),
184 "var" => Ok(Self::Var),
185 x => Err(format!("Unknown aggregate `{}`", x)),
186 }
187 }
188}
189
190#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, TS)]
191#[serde()]
192pub enum MultiAggregate {
193 #[serde(rename = "weighted mean")]
194 WeightedMean,
195}
196
197impl Display for MultiAggregate {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 MultiAggregate::WeightedMean => write!(f, "weighted mean"),
201 }
202 }
203}
204
205#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, TS)]
206#[serde(untagged)]
207pub enum Aggregate {
208 SingleAggregate(SingleAggregate),
209 MultiAggregate(MultiAggregate, String),
210}
211
212impl From<&'static str> for Aggregate {
213 fn from(value: &'static str) -> Self {
214 Self::from_str(value).expect("Unknown aggregate")
215 }
216}
217
218impl Display for Aggregate {
219 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
220 match self {
221 Self::SingleAggregate(x) => write!(fmt, "{}", x)?,
222 Self::MultiAggregate(MultiAggregate::WeightedMean, x) => {
223 write!(fmt, "weighted mean by {}", x)?
224 },
225 };
226 Ok(())
227 }
228}
229
230impl FromStr for Aggregate {
231 type Err = String;
232
233 fn from_str(input: &str) -> Result<Self, String> {
234 Ok(
235 if let Some(stripped) = input.strip_prefix("weighted mean by ") {
236 Self::MultiAggregate(MultiAggregate::WeightedMean, stripped.to_owned())
237 } else {
238 Self::SingleAggregate(SingleAggregate::from_str(input)?)
239 },
240 )
241 }
242}
243
244const STRING_AGGREGATES: &[SingleAggregate] = &[
245 SingleAggregate::Any,
246 SingleAggregate::Count,
247 SingleAggregate::DistinctCount,
248 SingleAggregate::Dominant,
249 SingleAggregate::First,
250 SingleAggregate::Join,
251 SingleAggregate::Last,
252 SingleAggregate::LastByIndex,
253 SingleAggregate::Median,
254 SingleAggregate::Q1,
255 SingleAggregate::Q3,
256 SingleAggregate::Unique,
257];
258
259const NUMBER_AGGREGATES: &[SingleAggregate] = &[
260 SingleAggregate::AbsSum,
261 SingleAggregate::Any,
262 SingleAggregate::Avg,
263 SingleAggregate::Count,
264 SingleAggregate::DistinctCount,
265 SingleAggregate::Dominant,
266 SingleAggregate::First,
267 SingleAggregate::High,
268 SingleAggregate::Low,
269 SingleAggregate::Max,
270 SingleAggregate::Min,
271 SingleAggregate::HighMinusLow,
272 SingleAggregate::LastByIndex,
273 SingleAggregate::LastMinusFirst,
274 SingleAggregate::Last,
275 SingleAggregate::Mean,
276 SingleAggregate::Median,
277 SingleAggregate::Q1,
278 SingleAggregate::Q3,
279 SingleAggregate::PctSumParent,
280 SingleAggregate::PctSumGrandTotal,
281 SingleAggregate::StdDev,
282 SingleAggregate::Sum,
283 SingleAggregate::SumAbs,
284 SingleAggregate::SumNotNull,
285 SingleAggregate::Unique,
286 SingleAggregate::Var,
287];
288
289const DATETIME_AGGREGATES: &[SingleAggregate] = &[
290 SingleAggregate::Any,
291 SingleAggregate::Avg,
292 SingleAggregate::Count,
293 SingleAggregate::DistinctCount,
294 SingleAggregate::Dominant,
295 SingleAggregate::First,
296 SingleAggregate::High,
297 SingleAggregate::Low,
298 SingleAggregate::Max,
299 SingleAggregate::Min,
300 SingleAggregate::LastByIndex,
301 SingleAggregate::Last,
302 SingleAggregate::Median,
303 SingleAggregate::Q1,
304 SingleAggregate::Q3,
305 SingleAggregate::Unique,
306];
307
308impl proto::ColumnType {
309 pub fn aggregates_iter(&self) -> Box<dyn Iterator<Item = Aggregate>> {
310 match self {
311 Self::Date | Self::Datetime => Box::new(
312 DATETIME_AGGREGATES
313 .iter()
314 .map(|x| Aggregate::SingleAggregate(*x)),
315 ),
316 Self::Boolean | Self::String => Box::new(
317 STRING_AGGREGATES
318 .iter()
319 .map(|x| Aggregate::SingleAggregate(*x)),
320 ),
321 Self::Integer | Self::Float => Box::new(
322 NUMBER_AGGREGATES
323 .iter()
324 .map(|x| Aggregate::SingleAggregate(*x)),
325 ),
326 }
327 }
328
329 pub const fn default_aggregate(&self) -> Aggregate {
330 match self {
331 Self::Boolean | Self::Date | Self::Datetime | Self::String => {
332 Aggregate::SingleAggregate(SingleAggregate::Count)
333 },
334 Self::Integer | Self::Float => Aggregate::SingleAggregate(SingleAggregate::Sum),
335 }
336 }
337}
338
339impl From<Aggregate> for view_config::AggList {
340 fn from(value: Aggregate) -> Self {
341 view_config::AggList {
342 aggregations: match value {
343 Aggregate::SingleAggregate(x) => vec![format!("{}", x)],
344 Aggregate::MultiAggregate(x, y) => vec![format!("{}", x), format!("{}", y)],
345 },
346 }
347 }
348}
349
350impl From<view_config::AggList> for Aggregate {
351 fn from(value: view_config::AggList) -> Self {
352 Aggregate::SingleAggregate(
353 SingleAggregate::from_str(value.aggregations.first().unwrap()).unwrap(),
354 )
355 }
356}