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}