postgrest_query_parser/ast/
order.rs1use 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}