postgrest_query_parser/ast/
order.rs

1use std::fmt::Debug;
2use std::iter::Peekable;
3
4use crate::ast::{Ast, Error};
5use crate::lexer::{Lexer, SpanType};
6
7#[derive(Debug, PartialEq, Clone, Default)]
8pub struct Order {
9    pub fields: Vec<OrderItem>,
10}
11
12#[derive(Debug, PartialEq, Clone, Default)]
13pub struct OrderItem {
14    pub field: String,
15    pub operator: Operator,
16    pub nulls_position: Option<NullOption>,
17}
18
19#[derive(Debug, PartialEq, Clone)]
20pub enum Operator {
21    Asc,
22    Desc,
23}
24
25#[derive(Debug, PartialEq, Clone)]
26pub enum NullOption {
27    First,
28    Last,
29}
30
31impl Default for Operator {
32    fn default() -> Self {
33        Operator::Asc
34    }
35}
36
37impl Ast {
38    pub(crate) fn parse_order<T>(
39        input: &str,
40        tokens: &mut Peekable<Lexer<T>>,
41    ) -> Result<Order, Error>
42    where
43        T: Iterator<Item = char>,
44    {
45        let mut order = Order::default();
46        let mut order_item = OrderItem::default();
47        let mut field_set = false;
48        let mut path_length = 0;
49
50        while let Some(token) = tokens.next() {
51            match token.span_type {
52                SpanType::And => {
53                    break;
54                }
55                SpanType::String if field_set == false => {
56                    order_item.field = input[token.range].to_string();
57                    field_set = true;
58                }
59                SpanType::String if field_set == true => match &input[token.range.clone()] {
60                    "asc" => order_item.operator = Operator::Asc,
61                    "desc" => order_item.operator = Operator::Desc,
62                    "nullsfirst" => order_item.nulls_position = Some(NullOption::First),
63                    "nullslast" => order_item.nulls_position = Some(NullOption::Last),
64                    found => {
65                        return Err(Error::InvalidOrderDirection {
66                            found: found.to_string(),
67                            range: token.range,
68                        })
69                    }
70                },
71                SpanType::PathSeparator => {
72                    path_length += 1;
73                    if path_length > 2 {
74                        return Err(Error::invalid_token(
75                            SpanType::Separator,
76                            SpanType::PathSeparator,
77                            token.range,
78                        ));
79                    }
80                }
81                SpanType::Separator
82                    if tokens.peek() == None
83                        || tokens.peek().map(|x| x.span_type) == Some(SpanType::And) =>
84                {
85                    return Err(Error::TrailingComma { range: token.range });
86                }
87                SpanType::Separator => {
88                    order.fields.push(order_item);
89                    order_item = OrderItem::default();
90                    field_set = false;
91                    path_length = 0;
92                }
93                found => return Err(Error::invalid_token(SpanType::String, found, token.range)),
94            }
95        }
96
97        order.fields.push(order_item);
98
99        Ok(order)
100    }
101}
102
103#[test]
104fn simple_order() {
105    let input = "order=age";
106    let lexer = Lexer::new(input.chars());
107    let expected = Ast {
108        order: Some(Order {
109            fields: vec![OrderItem {
110                field: "age".to_string(),
111                operator: Operator::Asc,
112                nulls_position: None,
113            }],
114        }),
115        ..Default::default()
116    };
117    let out = Ast::from_lexer(input, lexer).unwrap();
118
119    assert_eq!(expected, out);
120}
121
122#[test]
123fn single_order_with_operator() {
124    let input = "order=age.desc";
125    let lexer = Lexer::new(input.chars());
126    let expected = Ast {
127        order: Some(Order {
128            fields: vec![OrderItem {
129                field: "age".to_string(),
130                operator: Operator::Desc,
131                nulls_position: None,
132            }],
133        }),
134        ..Default::default()
135    };
136    let out = Ast::from_lexer(input, lexer).unwrap();
137
138    assert_eq!(expected, out);
139}
140
141#[test]
142fn single_order_with_operator_and_nulls_option() {
143    let input = "order=age.desc.nullslast";
144    let lexer = Lexer::new(input.chars());
145    let expected = Ast {
146        order: Some(Order {
147            fields: vec![OrderItem {
148                field: "age".to_string(),
149                operator: Operator::Desc,
150                nulls_position: Some(NullOption::Last),
151            }],
152        }),
153        ..Default::default()
154    };
155    let out = Ast::from_lexer(input, lexer).unwrap();
156
157    assert_eq!(expected, out);
158}
159
160#[test]
161fn multiple_order() {
162    let input = "order=age.desc,height.asc,width.desc.nullsfirst";
163    let lexer = Lexer::new(input.chars());
164    let expected = Ast {
165        order: Some(Order {
166            fields: vec![
167                OrderItem {
168                    field: "age".to_string(),
169                    operator: Operator::Desc,
170                    nulls_position: None,
171                },
172                OrderItem {
173                    field: "height".to_string(),
174                    operator: Operator::Asc,
175                    nulls_position: None,
176                },
177                OrderItem {
178                    field: "width".to_string(),
179                    operator: Operator::Desc,
180                    nulls_position: Some(NullOption::First),
181                },
182            ],
183        }),
184        ..Default::default()
185    };
186    let out = Ast::from_lexer(input, lexer).unwrap();
187
188    assert_eq!(expected, out);
189}
190
191#[test]
192fn invalid_order_too_long_path() {
193    let input = "order=age.desc.nullsfirst.asc";
194    let lexer = Lexer::new(input.chars());
195    let out = Ast::from_lexer(input, lexer).unwrap_err();
196    let expected = Error::InvalidToken {
197        expected: SpanType::Separator,
198        found: SpanType::PathSeparator,
199        range: 25..26,
200    };
201    assert_eq!(expected, out);
202    assert_eq!(".asc", &input[25..]);
203}
204
205#[test]
206fn invalid_order_trailing_comma() {
207    let input = "order=age.desc,";
208    let lexer = Lexer::new(input.chars());
209    let out = Ast::from_lexer(input, lexer).unwrap_err();
210    let expected = Error::TrailingComma { range: 14..15 };
211    assert_eq!(expected, out);
212    assert_eq!(",", &input[14..]);
213}
214
215#[test]
216fn invalid_order_trailing_comma_with_next_item() {
217    let input = "order=age.desc,&age=eq.42";
218    let lexer = Lexer::new(input.chars());
219    let out = Ast::from_lexer(input, lexer).unwrap_err();
220    let expected = Error::TrailingComma { range: 14..15 };
221    assert_eq!(expected, out);
222    assert_eq!(",&", &input[14..16]);
223}