odatav4_parser/
ast.rs

1/// Filter expression AST nodes
2#[derive(Debug, Clone, PartialEq)]
3pub enum FilterExpression {
4    /// Comparison: field eq value
5    Comparison {
6        left: Box<FilterExpression>,
7        op: ComparisonOp,
8        right: Box<FilterExpression>,
9    },
10    /// Logical: expr and expr
11    Logical {
12        left: Box<FilterExpression>,
13        op: LogicalOp,
14        right: Box<FilterExpression>,
15    },
16    /// Unary not: not expr
17    Not(Box<FilterExpression>),
18    /// Arithmetic: expr add expr
19    Arithmetic {
20        left: Box<FilterExpression>,
21        op: ArithmeticOp,
22        right: Box<FilterExpression>,
23    },
24    /// Unary minus: -expr
25    UnaryMinus(Box<FilterExpression>),
26    /// Function call: contains(Name, 'value')
27    FunctionCall {
28        name: String,
29        args: Vec<FilterExpression>,
30    },
31    /// In operator: Name in ('A', 'B', 'C')
32    In {
33        field: Box<FilterExpression>,
34        values: Vec<FilterExpression>,
35    },
36    /// Lambda operator: Items/any(i: i/Value eq 5)
37    Lambda {
38        collection: String,
39        operator: LambdaOp,
40        variable: String,
41        predicate: Box<FilterExpression>,
42    },
43    /// Field reference
44    Field(String),
45    /// String literal
46    StringLiteral(String),
47    /// Number literal
48    NumberLiteral(f64),
49    /// Boolean literal
50    BooleanLiteral(bool),
51    /// Null literal
52    Null,
53    /// GUID literal
54    GuidLiteral(String),
55    /// Date literal
56    DateLiteral(String),
57}
58
59/// Comparison operators
60#[derive(Debug, Clone, PartialEq)]
61pub enum ComparisonOp {
62    Eq,  // eq
63    Ne,  // ne
64    Gt,  // gt
65    Ge,  // ge
66    Lt,  // lt
67    Le,  // le
68    Has, // has
69}
70
71/// Logical operators
72#[derive(Debug, Clone, PartialEq)]
73pub enum LogicalOp {
74    And, // and
75    Or,  // or
76}
77
78/// Arithmetic operators
79#[derive(Debug, Clone, PartialEq)]
80pub enum ArithmeticOp {
81    Add, // add
82    Sub, // sub
83    Mul, // mul
84    Div, // div
85    Mod, // mod
86}
87
88/// Lambda operators
89#[derive(Debug, Clone, PartialEq)]
90pub enum LambdaOp {
91    Any, // any
92    All, // all
93}
94
95/// Sort direction for ORDER BY
96#[derive(Debug, Clone, PartialEq)]
97pub enum SortDirection {
98    Asc,
99    Desc,
100}
101
102/// Order by item with field and direction
103#[derive(Debug, Clone, PartialEq)]
104pub struct OrderByItem {
105    pub field: String,
106    pub direction: SortDirection,
107}
108
109impl OrderByItem {
110    pub fn new(field: String, direction: SortDirection) -> Self {
111        Self { field, direction }
112    }
113}
114
115/// Expand item with nested options
116#[derive(Debug, Clone, PartialEq)]
117pub struct ExpandItem {
118    pub field: String,
119    pub options: Option<Box<QueryOptions>>,
120    pub levels: Option<u32>,
121}
122
123impl ExpandItem {
124    pub fn new(field: String) -> Self {
125        Self {
126            field,
127            options: None,
128            levels: None,
129        }
130    }
131}
132
133/// AST representation of parsed OData V4 query options
134#[derive(Debug, Clone, PartialEq)]
135pub struct QueryOptions {
136    pub select: Option<Vec<String>>,
137    pub top: Option<u32>,
138    pub skip: Option<u32>,
139    pub expand: Option<Vec<ExpandItem>>,
140    pub filter: Option<FilterExpression>,
141    pub orderby: Option<Vec<OrderByItem>>,
142    pub groupby: Option<Vec<String>>,
143    pub count: Option<bool>,
144    pub format: Option<String>,
145    pub id: Option<String>,
146    pub skiptoken: Option<String>,
147    pub search: Option<String>,
148}
149
150impl QueryOptions {
151    pub fn new() -> Self {
152        Self {
153            select: None,
154            top: None,
155            skip: None,
156            expand: None,
157            filter: None,
158            orderby: None,
159            groupby: None,
160            count: None,
161            format: None,
162            id: None,
163            skiptoken: None,
164            search: None,
165        }
166    }
167}
168
169impl Default for QueryOptions {
170    fn default() -> Self {
171        Self::new()
172    }
173}