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;
17
18use crate::proto::get_features_resp::{AggregateArgs, AggregateOptions, ColumnTypeOptions};
19use crate::proto::{ColumnType, GetFeaturesResp};
20
21/// Describes the capabilities supported by a virtual server handler.
22///
23/// This struct is returned by
24/// [`VirtualServerHandler::get_features`](super::VirtualServerHandler::get_features)
25/// to inform clients about which operations are available.
26#[derive(Debug, Default, Deserialize)]
27pub struct Features<'a> {
28    /// Whether group-by aggregation is supported.
29    #[serde(default)]
30    pub group_by: bool,
31
32    /// Whether split-by (pivot) operations are supported.
33    #[serde(default)]
34    pub split_by: bool,
35
36    /// Available filter operators per column type.
37    #[serde(default)]
38    pub filter_ops: IndexMap<ColumnType, Vec<Cow<'a, str>>>,
39
40    /// Available aggregate functions per column type.
41    #[serde(default)]
42    pub aggregates: IndexMap<ColumnType, Vec<AggSpec<'a>>>,
43
44    /// Whether sorting is supported.
45    #[serde(default)]
46    pub sort: bool,
47
48    /// Whether computed expressions are supported.
49    #[serde(default)]
50    pub expressions: bool,
51
52    /// Whether update callbacks are supported.
53    #[serde(default)]
54    pub on_update: bool,
55}
56
57/// Specification for an aggregate function.
58///
59/// Aggregates can either take no additional arguments ([`AggSpec::Single`])
60/// or require column type arguments ([`AggSpec::Multiple`]).
61#[derive(Debug, Deserialize)]
62#[serde(untagged)]
63pub enum AggSpec<'a> {
64    /// An aggregate function with no additional arguments.
65    Single(Cow<'a, str>),
66    /// An aggregate function that requires column type arguments.
67    Multiple(Cow<'a, str>, Vec<ColumnType>),
68}
69
70impl<'a> From<Features<'a>> for GetFeaturesResp {
71    fn from(value: Features<'a>) -> GetFeaturesResp {
72        GetFeaturesResp {
73            group_by: value.group_by,
74            split_by: value.split_by,
75            expressions: value.expressions,
76            on_update: value.on_update,
77            sort: value.sort,
78            aggregates: value
79                .aggregates
80                .iter()
81                .map(|(dtype, aggs)| {
82                    (*dtype as u32, AggregateOptions {
83                        aggregates: aggs
84                            .iter()
85                            .map(|agg| match agg {
86                                AggSpec::Single(cow) => AggregateArgs {
87                                    name: cow.to_string(),
88                                    args: vec![],
89                                },
90                                AggSpec::Multiple(cow, column_types) => AggregateArgs {
91                                    name: cow.to_string(),
92                                    args: column_types.iter().map(|x| *x as i32).collect(),
93                                },
94                            })
95                            .collect(),
96                    })
97                })
98                .collect(),
99            filter_ops: value
100                .filter_ops
101                .iter()
102                .map(|(ty, options)| {
103                    (*ty as u32, ColumnTypeOptions {
104                        options: options.iter().map(|x| (*x).to_string()).collect(),
105                    })
106                })
107                .collect(),
108        }
109    }
110}