Skip to main content

perspective_client/virtual_server/
features.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use std::borrow::Cow;
14
15use indexmap::IndexMap;
16use serde::{Deserialize, Serialize};
17use ts_rs::TS;
18
19use crate::config::GroupRollupMode;
20use crate::proto::get_features_resp::{AggregateArgs, AggregateOptions, ColumnTypeOptions};
21use crate::proto::{ColumnType, GetFeaturesResp};
22
23/// Describes the capabilities supported by a virtual server handler.
24///
25/// This struct is returned by
26/// [`VirtualServerHandler::get_features`](super::VirtualServerHandler::get_features)
27/// to inform clients about which operations are available.
28#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, TS)]
29pub struct Features<'a> {
30    /// Whether group-by aggregation is supported.
31    #[serde(default)]
32    #[ts(optional, as = "Option<_>")]
33    pub group_by: bool,
34
35    /// Which `group_by_rollup_mode` options are supported
36    #[serde(default)]
37    #[ts(optional, as = "Option<_>")]
38    pub group_rollup_mode: Vec<GroupRollupMode>,
39
40    /// Whether split-by (pivot) operations are supported.
41    #[serde(default)]
42    #[ts(optional, as = "Option<_>")]
43    pub split_by: bool,
44
45    /// Available filter operators per column type.
46    #[serde(default)]
47    #[ts(optional, as = "Option<_>")]
48    pub filter_ops: IndexMap<ColumnType, Vec<Cow<'a, str>>>,
49
50    /// Available aggregate functions per column type.
51    #[serde(default)]
52    #[ts(optional, as = "Option<_>")]
53    pub aggregates: IndexMap<ColumnType, Vec<AggSpec<'a>>>,
54
55    /// Whether sorting is supported.
56    #[serde(default)]
57    #[ts(optional, as = "Option<_>")]
58    pub sort: bool,
59
60    /// Whether computed expressions are supported.
61    #[serde(default)]
62    #[ts(optional, as = "Option<_>")]
63    pub expressions: bool,
64
65    /// Available window aggregates.
66    #[serde(default)]
67    #[ts(optional, as = "Option<_>")]
68    pub window_aggregates: IndexMap<ColumnType, Vec<crate::config::WindowAggregate>>,
69
70    /// Whether update callbacks are supported.
71    #[serde(default)]
72    #[ts(optional, as = "Option<_>")]
73    pub on_update: bool,
74
75    /// The data store has no reliable natural row order
76    #[serde(default)]
77    #[ts(optional, as = "Option<_>")]
78    pub unordered: bool,
79}
80
81/// Specification for an aggregate function.
82///
83/// Aggregates can either take no additional arguments ([`AggSpec::Single`])
84/// or require column type arguments ([`AggSpec::Multiple`]).
85#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
86#[serde(untagged)]
87pub enum AggSpec<'a> {
88    /// An aggregate function with no additional arguments.
89    Single(Cow<'a, str>),
90    /// An aggregate function that requires column type arguments.
91    Multiple(Cow<'a, str>, Vec<ColumnType>),
92}
93
94impl<'a> From<Features<'a>> for GetFeaturesResp {
95    fn from(value: Features<'a>) -> GetFeaturesResp {
96        GetFeaturesResp {
97            group_by: value.group_by,
98            group_rollup_mode: value
99                .group_rollup_mode
100                .iter()
101                .map(|x| crate::proto::GroupRollupMode::from(*x) as i32)
102                .collect(),
103            split_by: value.split_by,
104            expressions: value.expressions,
105            on_update: value.on_update,
106            sort: value.sort,
107            unordered: value.unordered,
108            window_aggregates: value
109                .window_aggregates
110                .iter()
111                .map(|(ty, aggs)| {
112                    (
113                        *ty as u32,
114                        crate::proto::get_features_resp::WindowAggregateOptions {
115                            options: aggs
116                                .iter()
117                                .map(|x| crate::proto::WindowAggregate::from(*x) as i32)
118                                .collect(),
119                        },
120                    )
121                })
122                .collect(),
123            aggregates: value
124                .aggregates
125                .iter()
126                .map(|(dtype, aggs)| {
127                    (*dtype as u32, AggregateOptions {
128                        aggregates: aggs
129                            .iter()
130                            .map(|agg| match agg {
131                                AggSpec::Single(cow) => AggregateArgs {
132                                    name: cow.to_string(),
133                                    args: vec![],
134                                },
135                                AggSpec::Multiple(cow, column_types) => AggregateArgs {
136                                    name: cow.to_string(),
137                                    args: column_types.iter().map(|x| *x as i32).collect(),
138                                },
139                            })
140                            .collect(),
141                    })
142                })
143                .collect(),
144            filter_ops: value
145                .filter_ops
146                .iter()
147                .map(|(ty, options)| {
148                    (*ty as u32, ColumnTypeOptions {
149                        options: options.iter().map(|x| (*x).to_string()).collect(),
150                    })
151                })
152                .collect(),
153        }
154    }
155}