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, Hash, Ord, PartialEq, PartialOrd, Serialize, TS)]
191#[serde()]
192pub enum MultiAggregate {
193 #[serde(rename = "weighted mean")]
194 WeightedMean,
195
196 #[serde(rename = "max by")]
197 MaxBy,
198
199 #[serde(rename = "min by")]
200 MinBy,
201}
202
203impl Display for MultiAggregate {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 match self {
206 MultiAggregate::WeightedMean => write!(f, "weighted mean"),
207 MultiAggregate::MaxBy => write!(f, "max by"),
208 MultiAggregate::MinBy => write!(f, "min by"),
209 }
210 }
211}
212
213#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, TS)]
214#[serde(untagged)]
215pub enum Aggregate {
216 SingleAggregate(SingleAggregate),
217 MultiAggregate(MultiAggregate, String),
218}
219
220impl From<&'static str> for Aggregate {
221 fn from(value: &'static str) -> Self {
222 Self::from_str(value).expect("Unknown aggregate")
223 }
224}
225
226impl Display for Aggregate {
227 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
228 match self {
229 Self::SingleAggregate(x) => write!(fmt, "{x}")?,
230 Self::MultiAggregate(MultiAggregate::WeightedMean, x) => {
231 write!(fmt, "weighted mean by {x}")?
232 },
233 Self::MultiAggregate(MultiAggregate::MaxBy, x) => write!(fmt, "max by {x}")?,
234 Self::MultiAggregate(MultiAggregate::MinBy, x) => write!(fmt, "min by {x}")?,
235 };
236 Ok(())
237 }
238}
239
240impl FromStr for Aggregate {
241 type Err = String;
242
243 fn from_str(input: &str) -> Result<Self, String> {
244 Ok(
245 if let Some(stripped) = input.strip_prefix("weighted mean by ") {
246 Self::MultiAggregate(MultiAggregate::WeightedMean, stripped.to_owned())
247 } else if let Some(stripped) = input.strip_prefix("max by ") {
248 Self::MultiAggregate(MultiAggregate::MaxBy, stripped.to_owned())
249 } else if let Some(stripped) = input.strip_prefix("min by ") {
250 Self::MultiAggregate(MultiAggregate::MinBy, stripped.to_owned())
251 } else {
252 Self::SingleAggregate(SingleAggregate::from_str(input)?)
253 },
254 )
255 }
256}
257
258const STRING_AGGREGATES: &[SingleAggregate] = &[
259 SingleAggregate::Any,
260 SingleAggregate::Count,
261 SingleAggregate::DistinctCount,
262 SingleAggregate::Dominant,
263 SingleAggregate::First,
264 SingleAggregate::Join,
265 SingleAggregate::Last,
266 SingleAggregate::LastByIndex,
267 SingleAggregate::Median,
268 SingleAggregate::Q1,
269 SingleAggregate::Q3,
270 SingleAggregate::Unique,
271];
272
273const NUMBER_AGGREGATES: &[SingleAggregate] = &[
274 SingleAggregate::AbsSum,
275 SingleAggregate::Any,
276 SingleAggregate::Avg,
277 SingleAggregate::Count,
278 SingleAggregate::DistinctCount,
279 SingleAggregate::Dominant,
280 SingleAggregate::First,
281 SingleAggregate::High,
282 SingleAggregate::Low,
283 SingleAggregate::Max,
284 SingleAggregate::Min,
285 SingleAggregate::HighMinusLow,
286 SingleAggregate::LastByIndex,
287 SingleAggregate::LastMinusFirst,
288 SingleAggregate::Last,
289 SingleAggregate::Mean,
290 SingleAggregate::Median,
291 SingleAggregate::Q1,
292 SingleAggregate::Q3,
293 SingleAggregate::PctSumParent,
294 SingleAggregate::PctSumGrandTotal,
295 SingleAggregate::StdDev,
296 SingleAggregate::Sum,
297 SingleAggregate::SumAbs,
298 SingleAggregate::SumNotNull,
299 SingleAggregate::Unique,
300 SingleAggregate::Var,
301];
302
303const DATETIME_AGGREGATES: &[SingleAggregate] = &[
304 SingleAggregate::Any,
305 SingleAggregate::Avg,
306 SingleAggregate::Count,
307 SingleAggregate::DistinctCount,
308 SingleAggregate::Dominant,
309 SingleAggregate::First,
310 SingleAggregate::High,
311 SingleAggregate::Low,
312 SingleAggregate::Max,
313 SingleAggregate::Min,
314 SingleAggregate::LastByIndex,
315 SingleAggregate::Last,
316 SingleAggregate::Median,
317 SingleAggregate::Q1,
318 SingleAggregate::Q3,
319 SingleAggregate::Unique,
320];
321
322impl proto::ColumnType {
323 pub fn aggregates_iter(&self) -> Box<dyn Iterator<Item = Aggregate>> {
324 match self {
325 Self::Date | Self::Datetime => Box::new(
326 DATETIME_AGGREGATES
327 .iter()
328 .map(|x| Aggregate::SingleAggregate(*x)),
329 ),
330 Self::Boolean | Self::String => Box::new(
331 STRING_AGGREGATES
332 .iter()
333 .map(|x| Aggregate::SingleAggregate(*x)),
334 ),
335 Self::Integer | Self::Float => Box::new(
336 NUMBER_AGGREGATES
337 .iter()
338 .map(|x| Aggregate::SingleAggregate(*x)),
339 ),
340 }
341 }
342
343 pub const fn default_aggregate(&self) -> Aggregate {
344 match self {
345 Self::Boolean | Self::Date | Self::Datetime | Self::String => {
346 Aggregate::SingleAggregate(SingleAggregate::Count)
347 },
348 Self::Integer | Self::Float => Aggregate::SingleAggregate(SingleAggregate::Sum),
349 }
350 }
351}
352
353impl From<Aggregate> for view_config::AggList {
354 fn from(value: Aggregate) -> Self {
355 view_config::AggList {
356 aggregations: match value {
357 Aggregate::SingleAggregate(x) => vec![format!("{}", x)],
358 Aggregate::MultiAggregate(x, y) => vec![format!("{}", x), format!("{}", y)],
359 },
360 }
361 }
362}
363
364impl From<view_config::AggList> for Aggregate {
365 fn from(value: view_config::AggList) -> Self {
366 Aggregate::SingleAggregate(
367 SingleAggregate::from_str(value.aggregations.first().unwrap()).unwrap(),
368 )
369 }
370}