Skip to main content

openpql_pql_parser/ast/
selector.rs

1use super::{Error, Expr, Ident, ResultE, SelectorKind, String};
2
3/// Aggregate selector such as `avg(expr) as alias`.
4#[derive(Clone, PartialEq, derive_more::Debug)]
5#[debug("{:?}({:?}){}", self.kind, self.expr, _alias_to_str(self.alias.as_ref()))]
6pub struct Selector<'i> {
7    /// Aggregate kind.
8    pub kind: SelectorKind,
9    /// Inner expression the aggregate applies to.
10    pub expr: Expr<'i>,
11    /// Optional `as` alias.
12    pub alias: Option<Ident<'i>>,
13}
14
15fn _alias_to_str(alias: Option<&Ident>) -> String {
16    alias.map_or_else(String::default, |id| format!(" as {id:?}"))
17}
18
19impl<'i> Selector<'i> {
20    /// Builds a selector, resolving `kind` against the supported aggregates.
21    pub fn new(
22        kind: &Ident<'i>,
23        expr: Expr<'i>,
24        alias: Option<Ident<'i>>,
25    ) -> ResultE<'i, Self> {
26        let kind = match kind.inner.to_ascii_lowercase().as_str() {
27            "avg" => SelectorKind::Avg,
28            "count" => SelectorKind::Count,
29            "max" => SelectorKind::Max,
30            "min" => SelectorKind::Min,
31            _ => return Err(Error::UnrecognizedSelector(kind.loc).into()),
32        };
33
34        Ok(Self { kind, expr, alias })
35    }
36}
37
38#[cfg(test)]
39#[cfg_attr(coverage_nightly, coverage(off))]
40mod tests {
41    use crate::*;
42
43    fn assert_selector(src: &str, expected: &str) {
44        assert_eq!(format!("{:?}", parse_selector(src).unwrap()), expected);
45    }
46
47    #[test]
48    fn test_selector() {
49        assert_selector("avg(equity(hero, river))", "avg(equity(hero,river))");
50        assert_selector(
51            "avg(equity(hero, river)) as s1",
52            "avg(equity(hero,river)) as s1",
53        );
54
55        assert_selector("count(_)", "count(_)");
56        assert_selector("max(_)", "max(_)");
57        assert_selector("min(_)", "min(_)");
58    }
59
60    fn assert_err(src: &str, expected: Error) {
61        assert_eq!(parse_selector(src).unwrap_err(), expected);
62    }
63
64    #[test]
65    fn test_selector_err() {
66        let src = "invalid(_)";
67        assert_err(src, Error::UnrecognizedSelector(loc(src, "invalid")));
68    }
69}