perspective_client/config/
filters.rs1use std::fmt::Display;
14
15use itertools::Itertools;
16use serde::{Deserialize, Serialize};
17use ts_rs::TS;
18
19use crate::proto;
20use crate::proto::scalar;
21
22#[derive(Clone, Deserialize, Debug, PartialEq, Serialize, TS)]
25#[serde(untagged)]
26pub enum Scalar {
27 Float(f64),
28 String(String),
29 Bool(bool),
30 Null,
34}
35
36impl From<&str> for Scalar {
37 fn from(value: &str) -> Self {
38 Self::String(value.into())
39 }
40}
41
42impl Default for Scalar {
43 fn default() -> Self {
44 Self::Null
45 }
46}
47
48impl Display for Scalar {
49 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
50 match self {
51 Self::Float(x) => write!(fmt, "{x}"),
52 Self::String(x) => write!(fmt, "{x}"),
53 Self::Bool(x) => write!(fmt, "{x}"),
54 Self::Null => write!(fmt, ""),
55 }
56 }
57}
58
59#[derive(Clone, Deserialize, Debug, PartialEq, Serialize, TS)]
60#[serde(untagged)]
61pub enum FilterTerm {
62 Array(Vec<Scalar>),
63 Scalar(#[serde(default)] Scalar),
64}
65
66impl<'a, T> From<T> for FilterTerm
67where
68 T: AsRef<[&'a str]>,
69{
70 fn from(value: T) -> Self {
71 Self::Array(value.as_ref().iter().map(|x| (*x).into()).collect())
72 }
73}
74
75impl Default for FilterTerm {
76 fn default() -> Self {
77 Self::Scalar(Scalar::Null)
78 }
79}
80
81impl Display for FilterTerm {
82 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
83 match self {
84 Self::Scalar(x) => {
85 write!(fmt, "{x}")?;
86 },
87 Self::Array(xs) => write!(
88 fmt,
89 "{}",
90 Itertools::intersperse(xs.iter().map(|x| format!("{x}")), ",".to_owned())
91 .collect::<String>()
92 )?,
93 }
94
95 Ok(())
96 }
97}
98
99impl FilterTerm {
100 pub fn is_null(&self) -> bool {
101 matches!(self, FilterTerm::Scalar(Scalar::Null))
102 }
103}
104
105#[derive(Clone, Deserialize, Debug, PartialEq, Serialize, TS)]
106#[serde()]
107pub struct Filter(String, String, #[serde(default)] FilterTerm);
108
109impl Filter {
110 pub fn new<T>(column: &str, op: &str, term: T) -> Self
111 where
112 FilterTerm: From<T>,
113 {
114 Filter(column.to_string(), op.to_string(), term.into())
115 }
116
117 pub fn column(&self) -> &str {
118 self.0.as_str()
119 }
120
121 pub fn op(&self) -> &str {
122 self.1.as_str()
123 }
124
125 pub fn term(&self) -> &FilterTerm {
126 &self.2
127 }
128
129 pub fn column_mut(&mut self) -> &mut String {
130 &mut self.0
131 }
132
133 pub fn op_mut(&mut self) -> &mut String {
134 &mut self.1
135 }
136
137 pub fn term_mut(&mut self) -> &mut FilterTerm {
138 &mut self.2
139 }
140}
141
142#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)]
143pub enum FilterReducer {
144 #[serde(rename = "and")]
145 And,
146 #[serde(rename = "or")]
147 Or,
148}
149
150impl Default for FilterReducer {
151 fn default() -> Self {
152 Self::And
153 }
154}
155
156impl From<Scalar> for proto::Scalar {
157 fn from(value: Scalar) -> Self {
158 match value {
159 Scalar::Float(x) => proto::Scalar {
160 scalar: Some(scalar::Scalar::Float(x)),
161 },
162 Scalar::String(x) => proto::Scalar {
163 scalar: Some(scalar::Scalar::String(x)),
164 },
165 Scalar::Bool(x) => proto::Scalar {
166 scalar: Some(scalar::Scalar::Bool(x)),
167 },
168 Scalar::Null => proto::Scalar {
169 scalar: Some(scalar::Scalar::Null(0)),
170 },
171 }
172 }
173}
174
175impl From<proto::Scalar> for Scalar {
176 fn from(value: proto::Scalar) -> Self {
177 match value.scalar {
178 Some(scalar::Scalar::Bool(x)) => Scalar::Bool(x),
179 Some(scalar::Scalar::String(x)) => Scalar::String(x),
180 Some(scalar::Scalar::Float(x)) => Scalar::Float(x),
181 Some(scalar::Scalar::Null(_)) => Scalar::Null,
182 None => Scalar::Null,
183 }
184 }
185}
186
187impl From<Filter> for proto::view_config::Filter {
188 fn from(value: Filter) -> Self {
189 proto::view_config::Filter {
190 column: value.0,
191 op: value.1,
192 value: match value.2 {
193 FilterTerm::Scalar(x) => vec![x.into()],
194 FilterTerm::Array(x) => x.into_iter().map(|x| x.into()).collect(),
195 },
196 }
197 }
198}
199
200impl From<proto::view_config::Filter> for Filter {
201 fn from(value: proto::view_config::Filter) -> Self {
202 Filter(
203 value.column,
204 value.op,
205 if value.value.len() == 1 {
206 FilterTerm::Scalar(value.value.into_iter().next().unwrap().into())
207 } else {
208 FilterTerm::Array(value.value.into_iter().map(|x| x.into()).collect())
209 },
210 )
211 }
212}