perspective_client/config/
view_config.rs1use std::collections::HashMap;
14
15use serde::{Deserialize, Serialize};
16use ts_rs::TS;
17
18use super::aggregates::*;
19use super::expressions::*;
20use super::filters::*;
21use super::sort::*;
22use crate::proto;
23use crate::proto::columns_update;
24
25#[derive(Clone, Debug, Deserialize, Default, PartialEq, Serialize)]
26#[serde(deny_unknown_fields)]
27pub struct ViewConfig {
28 #[serde(default)]
29 pub group_by: Vec<String>,
30
31 #[serde(default)]
32 pub split_by: Vec<String>,
33
34 #[serde(default)]
35 pub columns: Vec<Option<String>>,
36
37 #[serde(default)]
38 pub filter: Vec<Filter>,
39
40 #[serde(skip_serializing_if = "is_default_value")]
41 #[serde(default)]
42 pub filter_op: FilterReducer,
43
44 #[serde(default)]
45 pub sort: Vec<Sort>,
46
47 #[serde(default)]
48 pub expressions: Expressions,
49
50 #[serde(default)]
51 pub aggregates: HashMap<String, Aggregate>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
54 #[serde(default)]
55 pub group_by_depth: Option<u32>,
56}
57
58fn is_default_value<A: Default + PartialEq>(value: &A) -> bool {
59 value == &A::default()
60}
61
62#[derive(Clone, Debug, Deserialize, Default, Serialize, TS)]
63#[serde(deny_unknown_fields)]
64pub struct ViewConfigUpdate {
65 #[serde(skip_serializing_if = "Option::is_none")]
66 #[serde(default)]
67 #[ts(optional)]
68 pub group_by: Option<Vec<String>>,
69
70 #[serde(skip_serializing_if = "Option::is_none")]
71 #[serde(default)]
72 #[ts(optional)]
73 pub split_by: Option<Vec<String>>,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
76 #[serde(default)]
77 #[ts(optional)]
78 pub columns: Option<Vec<Option<String>>>,
79
80 #[serde(skip_serializing_if = "Option::is_none")]
81 #[serde(default)]
82 #[ts(optional)]
83 pub filter: Option<Vec<Filter>>,
84
85 #[serde(skip_serializing_if = "Option::is_none")]
86 #[serde(default)]
87 #[ts(optional)]
88 pub filter_op: Option<FilterReducer>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
91 #[serde(default)]
92 #[ts(optional)]
93 pub sort: Option<Vec<Sort>>,
94
95 #[serde(skip_serializing_if = "Option::is_none")]
96 #[serde(default)]
97 #[ts(optional)]
98 pub expressions: Option<Expressions>,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
101 #[serde(default)]
102 #[ts(optional)]
103 pub aggregates: Option<HashMap<String, Aggregate>>,
104
105 #[serde(skip_serializing)]
106 #[serde(default)]
107 #[ts(optional)]
108 pub group_by_depth: Option<u32>,
109}
110
111impl From<ViewConfigUpdate> for proto::ViewConfig {
112 fn from(value: ViewConfigUpdate) -> Self {
113 proto::ViewConfig {
114 group_by: value.group_by.unwrap_or_default(),
115 split_by: value.split_by.unwrap_or_default(),
116 columns: value.columns.map(|x| proto::ColumnsUpdate {
117 opt_columns: Some(columns_update::OptColumns::Columns(
118 proto::columns_update::Columns {
119 columns: x.into_iter().flatten().collect(),
120 },
121 )),
122 }),
123 filter: value
124 .filter
125 .unwrap_or_default()
126 .into_iter()
127 .map(|x| x.into())
128 .collect(),
129 filter_op: value
130 .filter_op
131 .map(proto::view_config::FilterReducer::from)
132 .unwrap_or_default() as i32,
133 sort: value
134 .sort
135 .unwrap_or_default()
136 .into_iter()
137 .map(|x| x.into())
138 .collect(),
139 expressions: value.expressions.unwrap_or_default().0,
140 aggregates: value
141 .aggregates
142 .unwrap_or_default()
143 .into_iter()
144 .map(|(x, y)| (x, y.into()))
145 .collect(),
146 group_by_depth: value.group_by_depth,
147 }
148 }
149}
150
151impl From<FilterReducer> for proto::view_config::FilterReducer {
152 fn from(value: FilterReducer) -> Self {
153 match value {
154 FilterReducer::And => proto::view_config::FilterReducer::And,
155 FilterReducer::Or => proto::view_config::FilterReducer::Or,
156 }
157 }
158}
159
160impl From<proto::view_config::FilterReducer> for FilterReducer {
161 fn from(value: proto::view_config::FilterReducer) -> Self {
162 match value {
163 proto::view_config::FilterReducer::And => FilterReducer::And,
164 proto::view_config::FilterReducer::Or => FilterReducer::Or,
165 }
166 }
167}
168
169impl From<ViewConfig> for ViewConfigUpdate {
170 fn from(value: ViewConfig) -> Self {
171 ViewConfigUpdate {
172 group_by: Some(value.group_by),
173 split_by: Some(value.split_by),
174 columns: Some(value.columns),
175 filter: Some(value.filter),
176 filter_op: Some(value.filter_op),
177 sort: Some(value.sort),
178 expressions: Some(value.expressions),
179 aggregates: Some(value.aggregates),
180 group_by_depth: value.group_by_depth,
181 }
182 }
183}
184
185impl From<proto::ViewConfig> for ViewConfig {
186 fn from(value: proto::ViewConfig) -> Self {
187 ViewConfig {
188 group_by: value.group_by,
189 split_by: value.split_by,
190 columns: match value.columns.unwrap().opt_columns {
191 Some(columns_update::OptColumns::Columns(x)) => {
192 x.columns.into_iter().map(Some).collect()
193 },
194 _ => {
195 panic!("Expected columns in ViewConfig")
196 },
197 },
198 filter: value.filter.into_iter().map(|x| x.into()).collect(),
199 filter_op: proto::view_config::FilterReducer::try_from(value.filter_op)
200 .unwrap_or_default()
201 .into(),
202 sort: value.sort.into_iter().map(|x| x.into()).collect(),
203 expressions: Expressions(value.expressions),
204 aggregates: value
205 .aggregates
206 .into_iter()
207 .map(|(x, y)| (x, y.into()))
208 .collect(),
209 group_by_depth: value.group_by_depth,
210 }
211 }
212}
213
214impl ViewConfig {
215 fn _apply<T>(field: &mut T, update: Option<T>) -> bool {
216 match update {
217 None => false,
218 Some(update) => {
219 *field = update;
220 true
221 },
222 }
223 }
224
225 pub fn reset(&mut self, reset_expressions: bool) {
226 let mut config = Self::default();
227 if !reset_expressions {
228 config.expressions = self.expressions.clone();
229 }
230 std::mem::swap(self, &mut config);
231 }
232
233 pub fn apply_update(&mut self, update: ViewConfigUpdate) -> bool {
236 let mut changed = false;
237 changed = Self::_apply(&mut self.group_by, update.group_by) || changed;
238 changed = Self::_apply(&mut self.split_by, update.split_by) || changed;
239 changed = Self::_apply(&mut self.columns, update.columns) || changed;
240 changed = Self::_apply(&mut self.filter, update.filter) || changed;
241 changed = Self::_apply(&mut self.sort, update.sort) || changed;
242 changed = Self::_apply(&mut self.aggregates, update.aggregates) || changed;
243 changed = Self::_apply(&mut self.expressions, update.expressions) || changed;
244 changed
245 }
246
247 pub fn is_aggregated(&self) -> bool {
248 !self.group_by.is_empty()
249 }
250
251 pub fn is_column_expression_in_use(&self, name: &str) -> bool {
252 let name = name.to_owned();
253 self.group_by.contains(&name)
254 || self.split_by.contains(&name)
255 || self.sort.iter().any(|x| x.0 == name)
256 || self.filter.iter().any(|x| x.column() == name)
257 || self.columns.contains(&Some(name))
258 }
259
260 pub fn is_equivalent(&self, other: &Self) -> bool {
265 let _self = self.clone();
266 let _self = ViewConfig {
267 columns: _self.columns.into_iter().filter(|x| x.is_some()).collect(),
268 .._self
269 };
270
271 let _other = other.clone();
272 let _other = ViewConfig {
273 columns: _other.columns.into_iter().filter(|x| x.is_some()).collect(),
274 ..other.clone()
275 };
276
277 _self == _other
278 }
279}