tellaro_query_language/parser/
ast.rs1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(tag = "type", rename_all = "snake_case")]
11pub enum AstNode {
12 MatchAll,
14
15 Comparison(ComparisonNode),
17
18 LogicalOp(LogicalOpNode),
20
21 UnaryOp(UnaryOpNode),
23
24 CollectionOp(CollectionOpNode),
26
27 GeoExpr(GeoExprNode),
29
30 NslookupExpr(NslookupExprNode),
32
33 StatsExpr(StatsNode),
35
36 QueryWithStats(QueryWithStatsNode),
38}
39
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct ComparisonNode {
43 pub field: String,
45
46 pub operator: String,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub value: Option<Value>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub field_mutators: Option<Vec<Mutator>>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub value_mutators: Option<Vec<Mutator>>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub type_hint: Option<String>,
64}
65
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
68pub struct LogicalOpNode {
69 pub operator: String,
71
72 pub left: Box<AstNode>,
74
75 pub right: Box<AstNode>,
77}
78
79#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
81pub struct UnaryOpNode {
82 pub operator: String,
84
85 pub operand: Box<AstNode>,
87}
88
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
91pub struct CollectionOpNode {
92 pub operator: String,
94
95 pub field: String,
97
98 pub comparison_operator: String,
100
101 pub value: Value,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub field_mutators: Option<Vec<Mutator>>,
107
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub type_hint: Option<String>,
111}
112
113#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
115pub struct GeoExprNode {
116 pub field: String,
118
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub field_mutators: Option<Vec<Mutator>>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub type_hint: Option<String>,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub conditions: Option<Box<AstNode>>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub geo_params: Option<HashMap<String, Value>>,
134}
135
136#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
138pub struct NslookupExprNode {
139 pub field: String,
141
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub field_mutators: Option<Vec<Mutator>>,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub type_hint: Option<String>,
149
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub conditions: Option<Box<AstNode>>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub nslookup_params: Option<HashMap<String, Value>>,
157}
158
159#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
161pub struct StatsNode {
162 pub aggregations: Vec<Aggregation>,
164
165 #[serde(skip_serializing_if = "Vec::is_empty", default)]
167 pub group_by: Vec<GroupBy>,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub viz_hint: Option<String>,
172}
173
174#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
176pub struct QueryWithStatsNode {
177 pub filter: Box<AstNode>,
179
180 pub stats: StatsNode,
182}
183
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
186pub struct Aggregation {
187 pub function: String,
189
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub field: Option<String>,
193
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub alias: Option<String>,
197
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub modifier: Option<String>,
201
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub limit: Option<usize>,
205
206 #[serde(skip_serializing_if = "Option::is_none")]
208 pub percentile_values: Option<Vec<f64>>,
209
210 #[serde(skip_serializing_if = "Option::is_none")]
212 pub rank_values: Option<Vec<f64>>,
213
214 #[serde(skip_serializing_if = "Option::is_none")]
216 pub field_mutators: Option<Vec<Mutator>>,
217}
218
219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
221pub struct GroupBy {
222 pub field: String,
224
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub bucket_size: Option<usize>,
228}
229
230#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
232pub struct Mutator {
233 pub name: String,
235
236 #[serde(skip_serializing_if = "Vec::is_empty", default)]
238 pub args: Vec<Value>,
239}
240
241#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
243#[serde(untagged)]
244pub enum Value {
245 String(String),
247
248 Integer(i64),
250
251 Float(f64),
253
254 Boolean(bool),
256
257 List(Vec<Value>),
259
260 Null,
262}
263
264impl Value {
265 pub fn is_null(&self) -> bool {
267 matches!(self, Value::Null)
268 }
269
270 pub fn as_string(&self) -> Option<&str> {
272 match self {
273 Value::String(s) => Some(s),
274 _ => None,
275 }
276 }
277
278 pub fn as_integer(&self) -> Option<i64> {
280 match self {
281 Value::Integer(i) => Some(*i),
282 Value::Float(f) => Some(*f as i64),
283 _ => None,
284 }
285 }
286
287 pub fn as_float(&self) -> Option<f64> {
289 match self {
290 Value::Float(f) => Some(*f),
291 Value::Integer(i) => Some(*i as f64),
292 _ => None,
293 }
294 }
295
296 pub fn as_bool(&self) -> Option<bool> {
298 match self {
299 Value::Boolean(b) => Some(*b),
300 _ => None,
301 }
302 }
303
304 pub fn as_list(&self) -> Option<&Vec<Value>> {
306 match self {
307 Value::List(l) => Some(l),
308 _ => None,
309 }
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 #[test]
318 fn test_value_conversions() {
319 let str_val = Value::String("test".to_string());
320 assert_eq!(str_val.as_string(), Some("test"));
321 assert!(str_val.as_integer().is_none());
322
323 let int_val = Value::Integer(42);
324 assert_eq!(int_val.as_integer(), Some(42));
325 assert_eq!(int_val.as_float(), Some(42.0));
326
327 let null_val = Value::Null;
328 assert!(null_val.is_null());
329 }
330
331 #[test]
332 fn test_serialization() {
333 let node = ComparisonNode {
334 field: "test".to_string(),
335 operator: "eq".to_string(),
336 value: Some(Value::String("value".to_string())),
337 field_mutators: None,
338 value_mutators: None,
339 type_hint: None,
340 };
341
342 let json = serde_json::to_string(&node).unwrap();
343 assert!(json.contains("\"field\":\"test\""));
344 }
345}