Skip to main content

kernel/config/
aggregate.rs

1use std::hash::{Hash, Hasher};
2
3use serde::{Deserialize, Serialize};
4
5use crate::common;
6
7use super::{AggregateKey, Filter, FlussoType};
8
9/// Reduces rows from a related `table` to a single value — a count, sum, or
10/// extreme. The `key` connects the tables; `filters` restrict which rows of
11/// `table` count.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Aggregate {
14    pub table: common::TableName,
15    pub op: AggregateOp,
16    pub key: AggregateKey,
17    /// The declared result type. Fixed for `count` (`long`) and `avg` (`double`)
18    /// and left `None`; required for `sum` / `min` / `max`, whose result mirrors
19    /// the aggregated column and so must be stated to stay database-free.
20    #[serde(default, skip_serializing_if = "Option::is_none")]
21    pub value_type: Option<FlussoType>,
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub filters: Option<Vec<Filter>>,
24    /// Over a junction: count each target row once instead of once per
25    /// junction row. Only valid with an [`AggregateKey::Through`] key.
26    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
27    pub distinct: bool,
28}
29
30/// Hashes `distinct` only when set, so a schema that never opts in keeps the
31/// content hash (and so the physical index) it had before the field existed.
32impl Hash for Aggregate {
33    fn hash<H: Hasher>(&self, state: &mut H) {
34        let Self {
35            table,
36            op,
37            key,
38            value_type,
39            filters,
40            distinct,
41        } = self;
42        table.hash(state);
43        op.hash(state);
44        key.hash(state);
45        value_type.hash(state);
46        filters.hash(state);
47        if *distinct {
48            distinct.hash(state);
49        }
50    }
51}
52
53#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub enum AggregateOp {
56    Count,
57    Sum(common::ColumnName),
58    Avg(common::ColumnName),
59    Min(common::ColumnName),
60    Max(common::ColumnName),
61    /// Collect the related table's primary keys into a flat scalar array. The
62    /// element type is stated explicitly (the schema names it) so the array's
63    /// mapping is known without touching the database.
64    Ids {
65        element_type: FlussoType,
66    },
67}